Search in sources :

Example 1 with InvalidGeodeticParameterException

use of org.apache.sis.referencing.factory.InvalidGeodeticParameterException in project sis by apache.

the class Proj4Factory method name.

/**
 * Returns the {@literal Proj.4} name of the given parameter value or parameter group.
 *
 * @param  param    the parameter value or parameter group for which to get the Proj.4 name.
 * @param  errorKey the resource key of the error message to produce if no Proj.4 name has been found.
 *                  The message shall expect exactly one argument. This error key can be
 *                  {@link Errors.Keys#UnsupportedOperation_1} or {@link Errors.Keys#UnexpectedParameter_1}.
 * @return the Proj.4 name of the given object (never null).
 * @throws FactoryException if the Proj.4 name has not been found.
 */
private String name(final IdentifiedObject param, final short errorKey) throws FactoryException {
    String name = IdentifiedObjects.getName(param, Citations.PROJ4);
    if (name == null) {
        name = param.getName().getCode();
        final String message = Errors.getResources(defaultProperties).getString(errorKey, name);
        if (errorKey == Errors.Keys.UnsupportedOperation_1) {
            throw new NoSuchIdentifierException(message, name);
        } else {
            throw new InvalidGeodeticParameterException(message);
        }
    }
    return name;
}
Also used : InvalidGeodeticParameterException(org.apache.sis.referencing.factory.InvalidGeodeticParameterException) NoSuchIdentifierException(org.opengis.util.NoSuchIdentifierException) SimpleInternationalString(org.apache.sis.util.iso.SimpleInternationalString)

Example 2 with InvalidGeodeticParameterException

use of org.apache.sis.referencing.factory.InvalidGeodeticParameterException in project sis by apache.

the class DefaultMathTransformFactoryTest method testAllMapProjections.

/**
 * Tests the creation of all registered map projections.
 * Only the semi-axis lengths are specified. For the rest, we rely on default values.
 *
 * @throws FactoryException if the construction of a map projection failed.
 *
 * @since 0.7
 */
@Test
public void testAllMapProjections() throws FactoryException {
    /*
         * Gets all map projections and creates a projection using the WGS84 ellipsoid
         * and default parameter values.
         */
    final Map<String, ?> dummyName = Collections.singletonMap(DefaultProjectedCRS.NAME_KEY, "Test");
    final MathTransformFactory mtFactory = DefaultFactories.forBuildin(MathTransformFactory.class);
    final Collection<OperationMethod> methods = mtFactory.getAvailableMethods(Projection.class);
    for (final OperationMethod method : methods) {
        final String classification = method.getName().getCode();
        ParameterValueGroup param = mtFactory.getDefaultParameters(classification);
        param.parameter("semi_major").setValue(6377563.396);
        param.parameter("semi_minor").setValue(6356256.909237285);
        final MathTransform mt;
        try {
            mt = mtFactory.createParameterizedTransform(param);
        } catch (InvalidGeodeticParameterException e) {
            /*
                 * Some map projections have mandatory parameters which we ignore for now
                 * except for a few well-known projection that we know should not fail.
                 */
            if (classification.contains("Mercator")) {
                throw e;
            }
            out.print(classification);
            out.print(CharSequences.spaces(42 - classification.length()));
            out.print(": ");
            out.println(e.getLocalizedMessage());
            continue;
        }
        /*
             * Verifies that the map projection properties are the ones that we specified.
             * Note that the Equirectangular projection has been optimized as an affine transform, which we skip.
             */
        if (mt instanceof LinearTransform) {
            continue;
        }
        assertInstanceOf(classification, Parameterized.class, mt);
        param = ((Parameterized) mt).getParameterValues();
        assertEquals(classification, param.getDescriptor().getName().getCode());
        assertEquals(classification, 6377563.396, param.parameter("semi_major").doubleValue(), 1E-4);
        assertEquals(classification, 6356256.909237285, param.parameter("semi_minor").doubleValue(), 1E-4);
        /*
             * Creates a ProjectedCRS from the map projection. This part is more an integration test than
             * a DefaultMathTransformFactory test. Again, the intent is to verify that the properties are
             * the one that we specified.
             */
        final DefaultProjectedCRS crs = new DefaultProjectedCRS(dummyName, CommonCRS.WGS84.normalizedGeographic(), new DefaultConversion(dummyName, method, mt, null), HardCodedCS.PROJECTED);
        final Conversion projection = crs.getConversionFromBase();
        assertSame(classification, mt, projection.getMathTransform());
        assertEquals(classification, projection.getMethod().getName().getCode());
    }
}
Also used : InvalidGeodeticParameterException(org.apache.sis.referencing.factory.InvalidGeodeticParameterException) MathTransform(org.opengis.referencing.operation.MathTransform) MathTransformFactory(org.opengis.referencing.operation.MathTransformFactory) ParameterValueGroup(org.opengis.parameter.ParameterValueGroup) DefaultConversion(org.apache.sis.referencing.operation.DefaultConversion) DefaultProjectedCRS(org.apache.sis.referencing.crs.DefaultProjectedCRS) Conversion(org.opengis.referencing.operation.Conversion) DefaultConversion(org.apache.sis.referencing.operation.DefaultConversion) OperationMethod(org.opengis.referencing.operation.OperationMethod) Test(org.junit.Test)

Example 3 with InvalidGeodeticParameterException

use of org.apache.sis.referencing.factory.InvalidGeodeticParameterException in project sis by apache.

the class CoordinateOperationRegistry method propagateVertical.

/**
 * Appends a vertical axis in the source CRS of the first step {@code forward = true} or in
 * the target CRS of the last step {@code forward = false} of the given operations chain.
 *
 * @param  source3D    the potentially three-dimensional source CRS
 * @param  target3D    the potentially three-dimensional target CRS
 * @param  operations  the chain of operations in which to add a vertical axis.
 * @param  forward     {@code true} for adding the vertical axis at the beginning, or
 *                     {@code false} for adding the vertical axis at the end.
 * @return {@code true} on success.
 * @throws IllegalArgumentException if the operation method can not have the desired number of dimensions.
 */
private boolean propagateVertical(final CoordinateReferenceSystem source3D, final CoordinateReferenceSystem target3D, final ListIterator<CoordinateOperation> operations, final boolean forward) throws IllegalArgumentException, FactoryException {
    while (forward ? operations.hasNext() : operations.hasPrevious()) {
        final CoordinateOperation op = forward ? operations.next() : operations.previous();
        /*
             * We will accept to increase the number of dimensions only for operations between geographic CRS.
             * We do not increase the number of dimensions for operations between other kind of CRS because we
             * would not know which value to give to the new dimension.
             */
        CoordinateReferenceSystem sourceCRS, targetCRS;
        if (!((sourceCRS = op.getSourceCRS()) instanceof GeodeticCRS && (targetCRS = op.getTargetCRS()) instanceof GeodeticCRS && sourceCRS.getCoordinateSystem() instanceof EllipsoidalCS && targetCRS.getCoordinateSystem() instanceof EllipsoidalCS)) {
            break;
        }
        /*
             * We can process mostly linear operations, otherwise it is hard to know how to add a dimension.
             * Examples of linear operations are:
             *
             *   - Longitude rotation (EPSG:9601). Note that this is a transformation rather than a conversion.
             *   - Geographic3D to 2D conversion (EPSG:9659).
             *
             * However there is a few special cases where we may be able to add a dimension in a non-linear operation.
             * We can attempt those special cases by just giving the same parameters to the math transform factory
             * together with the desired CRS. Examples of such special cases are:
             *
             *   - Geocentric translations (geog2D domain)
             *   - Coordinate Frame Rotation (geog2D domain)
             *   - Position Vector transformation (geog2D domain)
             */
        Matrix matrix = MathTransforms.getMatrix(op.getMathTransform());
        if (matrix == null) {
            if (SubTypes.isSingleOperation(op)) {
                final MathTransformFactory mtFactory = factorySIS.getMathTransformFactory();
                if (mtFactory instanceof DefaultMathTransformFactory) {
                    if (forward)
                        sourceCRS = toGeodetic3D(sourceCRS, source3D);
                    else
                        targetCRS = toGeodetic3D(targetCRS, target3D);
                    final MathTransform mt;
                    try {
                        mt = ((DefaultMathTransformFactory) mtFactory).createParameterizedTransform(((SingleOperation) op).getParameterValues(), ReferencingUtilities.createTransformContext(sourceCRS, targetCRS, null));
                    } catch (InvalidGeodeticParameterException e) {
                        log(null, e);
                        break;
                    }
                    operations.set(recreate(op, sourceCRS, targetCRS, mt, mtFactory.getLastMethodUsed()));
                    return true;
                }
            }
            break;
        }
        /*
             * We can process only one of the following cases:
             *
             *   - Replace a 2D → 2D operation by a 3D → 3D one (i.e. add a passthrough operation).
             *   - Usually remove (or otherwise edit) the operation that change the number of dimensions
             *     between the 2D and 3D cases.
             */
        final int numRow = matrix.getNumRow();
        final int numCol = matrix.getNumCol();
        // 2D → 2D operation.
        final boolean is2D = (numCol == 3 && numRow == 3);
        if (!(is2D || (// 2D → 3D operation.
        forward ? // 2D → 3D operation.
        (numCol == 3 && numRow == 4) : // 3D → 2D operation.
        (numCol == 4 && numRow == 3)))) {
            break;
        }
        matrix = Matrices.resizeAffine(matrix, 4, 4);
        if (matrix.isIdentity()) {
            operations.remove();
        } else {
            /*
                 * If we can not just remove the operation, build a new one with the expected number of dimensions.
                 * The new operation will inherit the same properties except the identifiers, since it is no longer
                 * conform to the definition provided by the authority.
                 */
            final MathTransform mt = factorySIS.getMathTransformFactory().createAffineTransform(matrix);
            operations.set(recreate(op, toGeodetic3D(sourceCRS, source3D), toGeodetic3D(targetCRS, target3D), mt, null));
        }
        /*
             * If we processed the operation that change the number of dimensions, we are done.
             */
        if (!is2D) {
            return true;
        }
    }
    return false;
}
Also used : InvalidGeodeticParameterException(org.apache.sis.referencing.factory.InvalidGeodeticParameterException) DefaultMathTransformFactory(org.apache.sis.referencing.operation.transform.DefaultMathTransformFactory) DefaultMathTransformFactory(org.apache.sis.referencing.operation.transform.DefaultMathTransformFactory) DeferredCoordinateOperation(org.apache.sis.internal.referencing.DeferredCoordinateOperation) EllipsoidalCS(org.opengis.referencing.cs.EllipsoidalCS) CoordinateReferenceSystem(org.opengis.referencing.crs.CoordinateReferenceSystem) GeodeticCRS(org.opengis.referencing.crs.GeodeticCRS)

Example 4 with InvalidGeodeticParameterException

use of org.apache.sis.referencing.factory.InvalidGeodeticParameterException in project sis by apache.

the class DefaultCoordinateOperationFactory method createConcatenatedOperation.

/**
 * Creates an ordered sequence of two or more single coordinate operations.
 * The sequence of operations is constrained by the requirement that the source coordinate reference system
 * of step (<var>n</var>+1) must be the same as the target coordinate reference system of step (<var>n</var>).
 * The source coordinate reference system of the first step and the target coordinate reference system of the
 * last step are the source and target coordinate reference system associated with the concatenated operation.
 *
 * <p>The properties given in argument follow the same rules than for any other
 * {@linkplain AbstractCoordinateOperation#AbstractCoordinateOperation(Map, CoordinateReferenceSystem,
 * CoordinateReferenceSystem, CoordinateReferenceSystem, MathTransform) coordinate operation} constructor.
 * The following table is a reminder of main (not all) properties:</p>
 *
 * <table class="sis">
 *   <caption>Recognized properties (non exhaustive list)</caption>
 *   <tr>
 *     <th>Property name</th>
 *     <th>Value type</th>
 *     <th>Returned by</th>
 *   </tr>
 *   <tr>
 *     <td>{@value org.opengis.referencing.IdentifiedObject#NAME_KEY}</td>
 *     <td>{@link org.opengis.metadata.Identifier} or {@link String}</td>
 *     <td>{@link AbstractCoordinateOperation#getName()}</td>
 *   </tr>
 *   <tr>
 *     <td>{@value org.opengis.referencing.IdentifiedObject#IDENTIFIERS_KEY}</td>
 *     <td>{@link org.opengis.metadata.Identifier} (optionally as array)</td>
 *     <td>{@link AbstractCoordinateOperation#getIdentifiers()}</td>
 *   </tr>
 * </table>
 *
 * @param  properties  the properties to be given to the identified object.
 * @param  operations  the sequence of operations. Shall contains at least two operations.
 * @return the concatenated operation created from the given arguments.
 * @throws FactoryException if the object creation failed.
 */
@Override
public CoordinateOperation createConcatenatedOperation(final Map<String, ?> properties, final CoordinateOperation... operations) throws FactoryException {
    /*
         * If the user specified a single operation, there is no need to create a ConcatenatedOperation;
         * the operation to return will be the specified one. The metadata given in argument are ignored
         * on the assumption that the single operation has more complete metadata (in particular an EPSG
         * code, in which case we do not want to modify any other metadata in order to stay compliant
         * with EPSG definition).
         */
    if (operations != null && operations.length == 1) {
        return operations[0];
    }
    final ConcatenatedOperation op;
    try {
        op = new DefaultConcatenatedOperation(properties, operations, getMathTransformFactory());
    } catch (IllegalArgumentException exception) {
        throw new InvalidGeodeticParameterException(exception.getLocalizedMessage(), exception);
    }
    /*
         * Verifies again the number of single operations.  We may have a singleton if some operations
         * were omitted because their associated math transform were identity. This happen for example
         * if a "Geographic 3D to 2D conversion" has been redimensioned to a "3D to 3D" operation.
         */
    final List<? extends CoordinateOperation> co = op.getOperations();
    if (co.size() != 1) {
        return pool.unique(op);
    }
    final CoordinateOperation single = co.get(0);
    assert op.getMathTransform().equals(single.getMathTransform()) : op;
    if (!Objects.equals(single.getSourceCRS(), op.getSourceCRS()) || !Objects.equals(single.getTargetCRS(), op.getTargetCRS())) {
        /*
             * The CRS of the single operation may be different than the CRS of the concatenated operation
             * if the first or the last operation was an identity operation. It happens for example if the
             * sole purpose of an operation step was to change the longitude range from [-180 … +180]° to
             * [0 … 360]°: the MathTransform is identity (because Apache SIS does not handle those changes
             * in MathTransform; we handle that elsewhere, for example in the Envelopes utility class),
             * but omitting the transform should not cause the lost of the CRS with desired longitude range.
             */
        if (single instanceof SingleOperation) {
            final Map<String, Object> merge = new HashMap<>(IdentifiedObjects.getProperties(single, CoordinateOperation.IDENTIFIERS_KEY));
            merge.put(ReferencingServices.PARAMETERS_KEY, ((SingleOperation) single).getParameterValues());
            if (single instanceof AbstractIdentifiedObject) {
                merge.put(ReferencingServices.OPERATION_TYPE_KEY, ((AbstractIdentifiedObject) single).getInterface());
            }
            merge.putAll(properties);
            return createSingleOperation(merge, op.getSourceCRS(), op.getTargetCRS(), AbstractCoordinateOperation.getInterpolationCRS(op), ((SingleOperation) single).getMethod(), single.getMathTransform());
        }
    }
    return single;
}
Also used : InvalidGeodeticParameterException(org.apache.sis.referencing.factory.InvalidGeodeticParameterException) AbstractIdentifiedObject(org.apache.sis.referencing.AbstractIdentifiedObject) HashMap(java.util.HashMap) IdentifiedObject(org.opengis.referencing.IdentifiedObject) AbstractIdentifiedObject(org.apache.sis.referencing.AbstractIdentifiedObject)

Example 5 with InvalidGeodeticParameterException

use of org.apache.sis.referencing.factory.InvalidGeodeticParameterException in project sis by apache.

the class LinearTransformBuilder method create.

/**
 * Creates a linear transform approximation from the source positions to the target positions.
 * This method assumes that source positions are precise and that all uncertainty is in the target positions.
 *
 * @param  factory  the factory to use for creating the transform, or {@code null} for the default factory.
 *                  The {@link MathTransformFactory#createAffineTransform(Matrix)} method of that factory
 *                  shall return {@link LinearTransform} instances.
 * @return the fitted linear transform.
 * @throws FactoryException if the transform can not be created,
 *         for example because the source or target points have not be specified.
 *
 * @since 0.8
 */
@Override
@SuppressWarnings("serial")
public LinearTransform create(final MathTransformFactory factory) throws FactoryException {
    if (transform == null) {
        // Protect from changes.
        final double[][] sources = this.sources;
        final double[][] targets = this.targets;
        if (targets == null) {
            throw new InvalidGeodeticParameterException(noData());
        }
        final int sourceDim = (sources != null) ? sources.length : gridSize.length;
        final int targetDim = targets.length;
        correlation = new double[targetDim];
        final MatrixSIS matrix = Matrices.create(targetDim + 1, sourceDim + 1, ExtendedPrecisionMatrix.ZERO);
        matrix.setElement(targetDim, sourceDim, 1);
        for (int j = 0; j < targetDim; j++) {
            final double c;
            switch(sourceDim) {
                case 1:
                    {
                        final int row = j;
                        final Line line = new Line() {

                            @Override
                            public void setEquation(final Number slope, final Number y0) {
                                super.setEquation(slope, y0);
                                // Preserve the extended precision (double-double).
                                matrix.setNumber(row, 0, slope);
                                matrix.setNumber(row, 1, y0);
                            }
                        };
                        if (sources != null) {
                            c = line.fit(vector(sources[0]), vector(targets[j]));
                        } else {
                            c = line.fit(Vector.createSequence(0, 1, gridSize[0]), Vector.create(targets[j], false));
                        }
                        break;
                    }
                case 2:
                    {
                        final int row = j;
                        final Plane plan = new Plane() {

                            @Override
                            public void setEquation(final Number sx, final Number sy, final Number z0) {
                                super.setEquation(sx, sy, z0);
                                // Preserve the extended precision (double-double).
                                matrix.setNumber(row, 0, sx);
                                matrix.setNumber(row, 1, sy);
                                matrix.setNumber(row, 2, z0);
                            }
                        };
                        if (sources != null) {
                            c = plan.fit(vector(sources[0]), vector(sources[1]), vector(targets[j]));
                        } else
                            try {
                                c = plan.fit(gridSize[0], gridSize[1], Vector.create(targets[j], false));
                            } catch (IllegalArgumentException e) {
                                // This may happen if the z vector still contain some "NaN" values.
                                throw new InvalidGeodeticParameterException(noData(), e);
                            }
                        break;
                    }
                default:
                    {
                        throw new FactoryException(Errors.format(Errors.Keys.ExcessiveNumberOfDimensions_1, sourceDim));
                    }
            }
            correlation[j] = c;
        }
        transform = (LinearTransform) nonNull(factory).createAffineTransform(matrix);
    }
    return transform;
}
Also used : Line(org.apache.sis.math.Line) InvalidGeodeticParameterException(org.apache.sis.referencing.factory.InvalidGeodeticParameterException) Plane(org.apache.sis.math.Plane) FactoryException(org.opengis.util.FactoryException) MatrixSIS(org.apache.sis.referencing.operation.matrix.MatrixSIS)

Aggregations

InvalidGeodeticParameterException (org.apache.sis.referencing.factory.InvalidGeodeticParameterException)12 MathTransform (org.opengis.referencing.operation.MathTransform)5 FactoryException (org.opengis.util.FactoryException)3 ParserException (javax.measure.format.ParserException)2 UnavailableFactoryException (org.apache.sis.referencing.factory.UnavailableFactoryException)2 Test (org.junit.Test)2 OperationMethod (org.opengis.referencing.operation.OperationMethod)2 NoSuchIdentifierException (org.opengis.util.NoSuchIdentifierException)2 Constructor (java.lang.reflect.Constructor)1 PrivilegedAction (java.security.PrivilegedAction)1 HashMap (java.util.HashMap)1 DeferredCoordinateOperation (org.apache.sis.internal.referencing.DeferredCoordinateOperation)1 Parser (org.apache.sis.io.wkt.Parser)1 Line (org.apache.sis.math.Line)1 Plane (org.apache.sis.math.Plane)1 AbstractIdentifiedObject (org.apache.sis.referencing.AbstractIdentifiedObject)1 DefaultProjectedCRS (org.apache.sis.referencing.crs.DefaultProjectedCRS)1 DefaultConversion (org.apache.sis.referencing.operation.DefaultConversion)1 DefaultOperationMethod (org.apache.sis.referencing.operation.DefaultOperationMethod)1 MatrixSIS (org.apache.sis.referencing.operation.matrix.MatrixSIS)1