Search in sources :

Example 6 with ParameterValue

use of org.opengis.parameter.ParameterValue in project sis by apache.

the class InverseOperationMethod method properties.

/**
 * Infers the properties to give to an inverse coordinate operation.
 * The returned map will contains three kind of information:
 *
 * <ul>
 *   <li>Metadata (domain of validity, accuracy)</li>
 *   <li>Parameter values, if possible</li>
 * </ul>
 *
 * This method copies accuracy and domain of validity metadata from the given operation.
 * We presume that the inverse operation has the same accuracy than the direct operation.
 *
 * <div class="note"><b>Note:</b>
 * in many cases, the inverse operation is numerically less accurate than the direct operation because it
 * uses approximations like series expansions or iterative methods. However the numerical errors caused by
 * those approximations are not of interest here, because they are usually much smaller than the inaccuracy
 * due to the stochastic nature of coordinate transformations (not to be confused with coordinate conversions;
 * see ISO 19111 for more information).</div>
 *
 * If the inverse of the given operation can be represented by inverting the sign of all numerical
 * parameter values, then this method copies also those parameters in a {@code "parameters"} entry.
 *
 * @param source  the operation for which to get the inverse parameters.
 * @param target  where to store the inverse parameters.
 */
static void properties(final SingleOperation source, final Map<String, Object> target) {
    target.put(SingleOperation.DOMAIN_OF_VALIDITY_KEY, source.getDomainOfValidity());
    final Collection<PositionalAccuracy> accuracy = source.getCoordinateOperationAccuracy();
    if (!Containers.isNullOrEmpty(accuracy)) {
        target.put(SingleOperation.COORDINATE_OPERATION_ACCURACY_KEY, accuracy.toArray(new PositionalAccuracy[accuracy.size()]));
    }
    /*
         * If the inverse of the given operation can be represented by inverting the sign of all numerical
         * parameter values, copies those parameters in a "parameters" entry in the properties map.
         * Otherwise does nothing.
         */
    final ParameterValueGroup parameters = source.getParameterValues();
    final ParameterValueGroup copy = parameters.getDescriptor().createValue();
    for (final GeneralParameterValue gp : parameters.values()) {
        if (gp instanceof ParameterValue<?>) {
            final ParameterValue<?> src = (ParameterValue<?>) gp;
            final Object value = src.getValue();
            if (value instanceof Number) {
                final ParameterDescriptor<?> descriptor = src.getDescriptor();
                final InternationalString remarks = descriptor.getRemarks();
                if (remarks != SignReversalComment.SAME) {
                    if (remarks != SignReversalComment.OPPOSITE) {
                        /*
                             * The parameter descriptor does not specify whether the values for the inverse operation
                             * have the same sign or opposite sign. We could heuristically presume that we can invert
                             * the sign if the minimum value has the opposite sign than the maximum value  (as in the
                             * [-10 … 10] range), but such assumption is dangerous. For example the values in a matrix
                             * could be bounded to a range like [-1 … 1], which would mislead above heuristic rule.
                             *
                             * Note that abandoning here does not mean that we will never know the parameter values.
                             * As a fallback, AbstractCoordinateOperation will try to get the parameter values from
                             * the MathTransform. This is the appropriate thing to do at least for Affine operation.
                             */
                        return;
                    }
                    /*
                         * The parameter value of the inverse operation is (or is presumed to be) the negative of
                         * the parameter value of the source operation.  We need to preserve units of measurement
                         * if they were specified.
                         */
                    final ParameterValue<?> tgt = copy.parameter(descriptor.getName().getCode());
                    final Unit<?> unit = src.getUnit();
                    if (unit != null) {
                        tgt.setValue(-src.doubleValue(), unit);
                    } else if (value instanceof Integer || value instanceof Short || value instanceof Byte) {
                        tgt.setValue(-src.intValue());
                    } else {
                        tgt.setValue(-src.doubleValue());
                    }
                    // No need to add 'tgt' to 'copy' since it was done by the call to copy.parameter(…).
                    continue;
                }
            }
        }
        copy.values().add(gp);
    }
    target.put(ReferencingServices.PARAMETERS_KEY, copy);
}
Also used : GeneralParameterValue(org.opengis.parameter.GeneralParameterValue) PositionalAccuracy(org.opengis.metadata.quality.PositionalAccuracy) GeneralParameterValue(org.opengis.parameter.GeneralParameterValue) ParameterValue(org.opengis.parameter.ParameterValue) ParameterValueGroup(org.opengis.parameter.ParameterValueGroup) InternationalString(org.opengis.util.InternationalString)

Example 7 with ParameterValue

use of org.opengis.parameter.ParameterValue in project sis by apache.

the class WKTUtilities method append.

/**
 * Appends a {@linkplain ParameterValue parameter} in a {@code PARAMETER[…]} element.
 * If the supplied parameter is actually a {@linkplain ParameterValueGroup parameter group},
 * all contained parameters will be flattened in a single list.
 *
 * @param  parameter  the parameter to append to the WKT, or {@code null} if none.
 * @param  formatter  the formatter where to append the parameter.
 */
public static void append(GeneralParameterValue parameter, final Formatter formatter) {
    if (parameter instanceof ParameterValueGroup) {
        boolean first = true;
        for (final GeneralParameterValue param : ((ParameterValueGroup) parameter).values()) {
            if (first) {
                formatter.newLine();
                first = false;
            }
            append(param, formatter);
        }
    }
    if (parameter instanceof ParameterValue<?>) {
        if (!(parameter instanceof FormattableObject)) {
            parameter = new DefaultParameterValue<>((ParameterValue<?>) parameter);
        }
        formatter.append((FormattableObject) parameter);
        formatter.newLine();
    }
}
Also used : GeneralParameterValue(org.opengis.parameter.GeneralParameterValue) ParameterValue(org.opengis.parameter.ParameterValue) DefaultParameterValue(org.apache.sis.parameter.DefaultParameterValue) GeneralParameterValue(org.opengis.parameter.GeneralParameterValue) ParameterValueGroup(org.opengis.parameter.ParameterValueGroup) FormattableObject(org.apache.sis.io.wkt.FormattableObject)

Example 8 with ParameterValue

use of org.opengis.parameter.ParameterValue in project sis by apache.

the class CC_OperationMethod method store.

/**
 * Stores the given {@code parameters} into the given {@code addTo} collection.
 * This method copies only the <em>references</em> if possible. However is some
 * cases the values may need to be copied in new parameter instances.
 *
 * <div class="note"><b>Note:</b>
 * this code is defined in this {@code CC_OperationMethod} class instead than in the
 * {@link DefaultOperationMethod} class in the hope to reduce the amount of code processed
 * by the JVM in the common case where JAXB (un)marshalling is not needed.</div>
 *
 * @param  parameters    the parameters to add to the {@code addTo} collection.
 * @param  addTo         where to store the {@code parameters}.
 * @param  replacements  the replacements to apply in the {@code GeneralParameterValue} instances.
 */
public static void store(final GeneralParameterValue[] parameters, final Collection<GeneralParameterValue> addTo, final Map<GeneralParameterDescriptor, GeneralParameterDescriptor> replacements) {
    for (GeneralParameterValue p : parameters) {
        final GeneralParameterDescriptor replacement = replacements.get(p.getDescriptor());
        if (replacement != null) {
            if (p instanceof ParameterValue<?>) {
                final ParameterValue<?> source = (ParameterValue<?>) p;
                final ParameterValue<?> target = new DefaultParameterValue<>((ParameterDescriptor<?>) replacement);
                final Object value = source.getValue();
                final Unit<?> unit = source.getUnit();
                if (unit == null) {
                    target.setValue(value);
                } else if (value instanceof double[]) {
                    target.setValue((double[]) value, unit);
                } else {
                    target.setValue(((Number) value).doubleValue(), unit);
                }
                p = target;
            } else if (p instanceof ParameterValueGroup) {
                final ParameterValueGroup source = (ParameterValueGroup) p;
                final ParameterValueGroup target = new DefaultParameterValueGroup((ParameterDescriptorGroup) replacement);
                final Collection<GeneralParameterValue> values = source.values();
                store(values.toArray(new GeneralParameterValue[values.size()]), target.values(), replacements);
                p = target;
            }
        }
        addTo.add(p);
    }
}
Also used : DefaultParameterValue(org.apache.sis.parameter.DefaultParameterValue) GeneralParameterValue(org.opengis.parameter.GeneralParameterValue) ParameterValue(org.opengis.parameter.ParameterValue) DefaultParameterValue(org.apache.sis.parameter.DefaultParameterValue) GeneralParameterValue(org.opengis.parameter.GeneralParameterValue) DefaultParameterValueGroup(org.apache.sis.parameter.DefaultParameterValueGroup) ParameterValueGroup(org.opengis.parameter.ParameterValueGroup) ParameterDescriptorGroup(org.opengis.parameter.ParameterDescriptorGroup) DefaultParameterDescriptorGroup(org.apache.sis.parameter.DefaultParameterDescriptorGroup) GeneralParameterDescriptor(org.opengis.parameter.GeneralParameterDescriptor) DefaultParameterValueGroup(org.apache.sis.parameter.DefaultParameterValueGroup) Collection(java.util.Collection)

Example 9 with ParameterValue

use of org.opengis.parameter.ParameterValue in project sis by apache.

the class DefaultConversionTest method verifyProperties.

/**
 * Asserts that at least some of the properties of the given {@code op} instance have the expected values
 * for an instance created by {@link #createLongitudeRotation(GeographicCRS, GeographicCRS, TemporalCRS)}.
 */
@SuppressWarnings("SuspiciousToArrayCall")
private static void verifyProperties(final DefaultConversion op, final boolean swapSourceAxes) {
    assertEquals("name", "Paris to Greenwich", op.getName().getCode());
    assertEquals("sourceCRS", "NTF (Paris)", op.getSourceCRS().getName().getCode());
    assertEquals("targetCRS", "Back to Greenwich", op.getTargetCRS().getName().getCode());
    assertEquals("method", "Longitude rotation", op.getMethod().getName().getCode());
    assertEquals("parameters", "Longitude rotation", op.getParameterDescriptors().getName().getCode());
    final ParameterValueGroup parameters = op.getParameterValues();
    final ParameterValue<?>[] values = parameters.values().toArray(new ParameterValue<?>[1]);
    assertEquals("parameters", "Longitude rotation", parameters.getDescriptor().getName().getCode());
    assertEquals("parameters[0]", "Longitude offset", values[0].getDescriptor().getName().getCode());
    assertEquals("parameters[0]", OFFSET, values[0].doubleValue(), STRICT);
    assertEquals(1, values.length);
    final Matrix3 expected = new Matrix3();
    expected.m02 = OFFSET;
    if (swapSourceAxes) {
        expected.m00 = expected.m11 = 0;
        expected.m01 = expected.m10 = 1;
    }
    assertMatrixEquals("Longitude rotation of a two-dimensional CRS", expected, MathTransforms.getMatrix(op.getMathTransform()), STRICT);
}
Also used : ParameterValue(org.opengis.parameter.ParameterValue) ParameterValueGroup(org.opengis.parameter.ParameterValueGroup) Matrix3(org.apache.sis.referencing.operation.matrix.Matrix3)

Example 10 with ParameterValue

use of org.opengis.parameter.ParameterValue in project sis by apache.

the class Proj4 method definition.

/**
 * Infers a {@literal Proj.4} definition from the given projected, geographic or geocentric coordinate reference system.
 * This method does not need the Proj.4 native library; it can be used in a pure Java application.
 * However the returned definition string may differ depending on whether the Proj.4 library is available or not.
 *
 * @param  crs  the coordinate reference system for which to create a Proj.4 definition.
 * @return the definition of the given CRS in a Proj.4 format.
 * @throws FactoryException if the Proj.4 definition string can not be created from the given CRS.
 */
public static String definition(final CoordinateReferenceSystem crs) throws FactoryException {
    ArgumentChecks.ensureNonNull("crs", crs);
    /*
         * If the given CRS object is associated to a Proj.4 structure, let Proj.4 formats itself
         * the definition string. Note that this operation may fail if there is no Proj.4 library
         * in the current system, or no JNI bindings to that library.
         */
    try {
        for (final Identifier id : crs.getIdentifiers()) {
            if (id instanceof PJ) {
                return ((PJ) id).getCode();
            }
        }
    } catch (UnsatisfiedLinkError e) {
        // Thrown the first time that we try to use the library.
        Logging.unexpectedException(Logging.getLogger(Modules.GDAL), Proj4.class, "definition", e);
    } catch (NoClassDefFoundError e) {
        // Thrown on all attempts after the first one.
        Logging.recoverableException(Logging.getLogger(Modules.GDAL), Proj4.class, "definition", e);
    }
    /*
         * If we found no Proj.4 structure, formats the definition string ourself. The string may differ from
         * what Proj.4 would have given. In particular, we do not provide "+init=" or "+datum=" parameter.
         * But the definition should still be semantically equivalent.
         */
    final String method;
    final GeodeticDatum datum;
    final ParameterValueGroup parameters;
    final CoordinateSystem cs = crs.getCoordinateSystem();
    if (crs instanceof GeodeticCRS) {
        if (cs instanceof EllipsoidalCS) {
            method = "latlon";
        } else if (cs instanceof CartesianCS) {
            method = "geocent";
        } else {
            throw new FactoryException(Errors.format(Errors.Keys.UnsupportedCoordinateSystem_1, cs.getClass()));
        }
        datum = ((GeodeticCRS) crs).getDatum();
        parameters = null;
    } else if (crs instanceof ProjectedCRS) {
        Projection c = ((ProjectedCRS) crs).getConversionFromBase();
        datum = ((ProjectedCRS) crs).getDatum();
        method = name(c.getMethod());
        parameters = c.getParameterValues();
    } else {
        throw new FactoryException(Errors.format(Errors.Keys.UnsupportedType_1, crs.getClass()));
    }
    /*
         * Append the map projection parameters. Those parameters may include axis lengths (a and b),
         * but not necessarily. If axis lengths are specified, then we will ignore the Ellipsoid instance
         * associated to the CRS.
         */
    final StringBuilder definition = new StringBuilder(100);
    definition.append(Proj4Factory.PROJ_PARAM).append(method);
    boolean hasSemiMajor = false;
    boolean hasSemiMinor = false;
    if (parameters != null) {
        definition.append(Proj4Factory.STANDARD_OPTIONS);
        for (final GeneralParameterValue parameter : parameters.values()) {
            if (parameter instanceof ParameterValue<?>) {
                final ParameterValue<?> pv = (ParameterValue<?>) parameter;
                final Object value;
                Unit<?> unit = pv.getUnit();
                if (unit != null) {
                    unit = Units.isAngular(unit) ? Units.DEGREE : unit.getSystemUnit();
                    // Always in metres or degrees.
                    value = pv.doubleValue(unit);
                } else {
                    value = pv.getValue();
                    if (value == null) {
                        continue;
                    }
                }
                final String pn = name(parameter.getDescriptor());
                hasSemiMajor |= pn.equals("a");
                hasSemiMinor |= pn.equals("b");
                definition.append(" +").append(pn).append('=').append(value);
            }
        }
    }
    /*
         * Append datum information: axis lengths if they were not part of the parameters, then prime meridian.
         */
    final Ellipsoid ellipsoid = datum.getEllipsoid();
    if (!hasSemiMajor)
        definition.append(" +a=").append(ellipsoid.getSemiMajorAxis());
    if (!hasSemiMinor)
        definition.append(" +b=").append(ellipsoid.getSemiMinorAxis());
    final PrimeMeridian pm = datum.getPrimeMeridian();
    if (pm != null) {
        double lon = pm.getGreenwichLongitude();
        final Unit<Angle> unit = pm.getAngularUnit();
        if (unit != null) {
            lon = unit.getConverterTo(Units.DEGREE).convert(lon);
        }
        definition.append(" +pm=").append(lon);
    }
    /*
         * Appends axis directions. This method always format a vertical direction (up or down)
         * even if the coordinate system is two-dimensional, because Proj.4 seems to require it.
         * Also extract axis units in the process.
         */
    // Horizontal at index 0, vertical at index 1.
    final Unit<?>[] units = new Unit<?>[2];
    boolean validCS = true;
    definition.append(' ').append(Proj4Factory.AXIS_ORDER_PARAM);
    final int dimension = Math.min(cs.getDimension(), 3);
    boolean hasVertical = false;
    for (int i = 0; i < dimension; i++) {
        final CoordinateSystemAxis axis = cs.getAxis(i);
        final AxisDirection dir = axis.getDirection();
        int unitIndex = 0;
        if (!AxisDirections.isCardinal(dir)) {
            if (!AxisDirections.isVertical(dir)) {
                throw new FactoryException(Errors.format(Errors.Keys.UnsupportedAxisDirection_1, dir));
            }
            hasVertical = true;
            unitIndex = 1;
        }
        final Unit<?> old = units[unitIndex];
        units[unitIndex] = axis.getUnit();
        validCS &= (old == null || old.equals(units[unitIndex]));
        definition.appendCodePoint(Character.toLowerCase(dir.name().codePointAt(0)));
    }
    if (!hasVertical && dimension < 3) {
        // Add a UP direction if not already present.
        definition.append('u');
    }
    /*
         * Append units of measurement, then verify the coordinate system validity.
         */
    for (int i = 0; i < units.length; i++) {
        final Unit<?> unit = units[i];
        if (unit != null && !unit.equals(Units.DEGREE) && !unit.equals(Units.METRE)) {
            validCS &= Units.isLinear(unit);
            definition.append(" +");
            // "+vto_meter" parameter.
            if (i == 1)
                definition.append('v');
            definition.append("to_meter=").append(Units.toStandardUnit(unit));
        }
    }
    /*
         * Append the "+towgs84" element if any. This is the last piece of information.
         * Note that the use of a "+towgs84" parameter is an "early binding" approach,
         * which is usually not recommended. But Proj4 works that way.
         */
    if (validCS) {
        if (datum instanceof DefaultGeodeticDatum) {
            for (final BursaWolfParameters bwp : ((DefaultGeodeticDatum) datum).getBursaWolfParameters()) {
                if (Utilities.equalsIgnoreMetadata(CommonCRS.WGS84.datum(), bwp.getTargetDatum())) {
                    definition.append(" +towgs84=").append(bwp.tX).append(',').append(bwp.tY).append(',').append(bwp.tZ);
                    if (!bwp.isTranslation()) {
                        definition.append(',').append(bwp.rX).append(',').append(bwp.rY).append(',').append(bwp.rZ).append(',').append(bwp.dS);
                    }
                    break;
                }
            }
        }
        return definition.toString();
    }
    /*
         * If we reach this point, we detected a coordinate system that we can not format as a
         * Proj.4 definition string. Format an error message with axis directions and units.
         */
    definition.setLength(0);
    definition.append('(');
    for (int i = 0; i < units.length; i++) {
        final CoordinateSystemAxis axis = cs.getAxis(i);
        if (i != 0)
            definition.append(", ");
        definition.append(axis.getUnit()).append(' ').append(Types.getCodeName(axis.getDirection()));
    }
    throw new FactoryException(Errors.format(Errors.Keys.IllegalCoordinateSystem_1, definition.append(')')));
}
Also used : ParameterValueGroup(org.opengis.parameter.ParameterValueGroup) UnavailableFactoryException(org.apache.sis.referencing.factory.UnavailableFactoryException) FactoryException(org.opengis.util.FactoryException) CoordinateSystem(org.opengis.referencing.cs.CoordinateSystem) Projection(org.opengis.referencing.operation.Projection) CoordinateSystemAxis(org.opengis.referencing.cs.CoordinateSystemAxis) Unit(javax.measure.Unit) Identifier(org.opengis.metadata.Identifier) AxisDirection(org.opengis.referencing.cs.AxisDirection) EllipsoidalCS(org.opengis.referencing.cs.EllipsoidalCS) CartesianCS(org.opengis.referencing.cs.CartesianCS) GeneralParameterValue(org.opengis.parameter.GeneralParameterValue) ParameterValue(org.opengis.parameter.ParameterValue) GeneralParameterValue(org.opengis.parameter.GeneralParameterValue) GeodeticDatum(org.opengis.referencing.datum.GeodeticDatum) DefaultGeodeticDatum(org.apache.sis.referencing.datum.DefaultGeodeticDatum) GeodeticCRS(org.opengis.referencing.crs.GeodeticCRS) PrimeMeridian(org.opengis.referencing.datum.PrimeMeridian) ProjectedCRS(org.opengis.referencing.crs.ProjectedCRS) Angle(javax.measure.quantity.Angle) DefaultGeodeticDatum(org.apache.sis.referencing.datum.DefaultGeodeticDatum) IdentifiedObject(org.opengis.referencing.IdentifiedObject) BursaWolfParameters(org.apache.sis.referencing.datum.BursaWolfParameters) Ellipsoid(org.opengis.referencing.datum.Ellipsoid)

Aggregations

ParameterValue (org.opengis.parameter.ParameterValue)11 GeneralParameterValue (org.opengis.parameter.GeneralParameterValue)9 ParameterValueGroup (org.opengis.parameter.ParameterValueGroup)8 GeneralParameterDescriptor (org.opengis.parameter.GeneralParameterDescriptor)3 DefaultParameterValue (org.apache.sis.parameter.DefaultParameterValue)2 UnavailableFactoryException (org.apache.sis.referencing.factory.UnavailableFactoryException)2 Matrix3 (org.apache.sis.referencing.operation.matrix.Matrix3)2 DependsOnMethod (org.apache.sis.test.DependsOnMethod)2 Test (org.junit.Test)2 IdentifiedObject (org.opengis.referencing.IdentifiedObject)2 Matrix (org.opengis.referencing.operation.Matrix)2 ArrayList (java.util.ArrayList)1 Collection (java.util.Collection)1 Unit (javax.measure.Unit)1 Angle (javax.measure.quantity.Angle)1 CC_OperationParameterGroupTest (org.apache.sis.internal.jaxb.referencing.CC_OperationParameterGroupTest)1 FormattableObject (org.apache.sis.io.wkt.FormattableObject)1 DefaultParameterDescriptorGroup (org.apache.sis.parameter.DefaultParameterDescriptorGroup)1 DefaultParameterValueGroup (org.apache.sis.parameter.DefaultParameterValueGroup)1 BursaWolfParameters (org.apache.sis.referencing.datum.BursaWolfParameters)1