use of org.opengis.util.FactoryException in project sis by apache.
the class Geographic3Dto2DTest method createDatumShiftForGeographic2D.
/**
* Creates a "Geographic 2D to 3D → Geocentric → Affine → Geographic → Geographic 3D to 2D" chain.
* This method is used for integration tests.
*
* @param factory the math transform factory to use for creating and concatenating the transform.
* @param affine the math transform for the operation in geocentric Cartesian domain.
* @param pv the parameters for the operation in geographic coordinates.
* @return the chain of transforms.
* @throws FactoryException if an error occurred while creating a transform.
*
* @see GeocentricTranslationTest#createDatumShiftForGeographic2D(MathTransformFactory)
*/
static MathTransform createDatumShiftForGeographic2D(final MathTransformFactory factory, final MathTransform affine, final Parameters pv) throws FactoryException {
assertEquals("sourceDimensions", 3, affine.getSourceDimensions());
assertEquals("targetDimensions", 3, affine.getTargetDimensions());
/*
* Create a "Geographic to Geocentric" conversion with ellipsoid axis length units converted to metres
* (the unit implied by SRC_SEMI_MAJOR) because it is the unit of Bursa-Wolf parameters that we created above.
*/
Parameters step = Parameters.castOrWrap(factory.getDefaultParameters(GeographicToGeocentric.NAME));
step.getOrCreate(MapProjection.SEMI_MAJOR).setValue(pv.doubleValue(GeocentricAffineBetweenGeographic.SRC_SEMI_MAJOR));
step.getOrCreate(MapProjection.SEMI_MINOR).setValue(pv.doubleValue(GeocentricAffineBetweenGeographic.SRC_SEMI_MINOR));
MathTransform toGeocentric = factory.createParameterizedTransform(step);
assertEquals("sourceDimensions", 3, toGeocentric.getSourceDimensions());
assertEquals("targetDimensions", 3, toGeocentric.getTargetDimensions());
final MathTransform reduce = factory.createParameterizedTransform(factory.getDefaultParameters("Geographic3D to 2D conversion"));
assertEquals("sourceDimensions", 3, reduce.getSourceDimensions());
assertEquals("targetDimensions", 2, reduce.getTargetDimensions());
try {
toGeocentric = factory.createConcatenatedTransform(reduce.inverse(), toGeocentric);
} catch (NoninvertibleTransformException e) {
throw new FactoryException(e);
}
assertEquals("sourceDimensions", 2, toGeocentric.getSourceDimensions());
assertEquals("targetDimensions", 3, toGeocentric.getTargetDimensions());
/*
* Create a "Geocentric to Geographic" conversion with ellipsoid axis length units converted to metres
* because this is the unit of the Geocentric CRS used above.
*/
step = Parameters.castOrWrap(factory.getDefaultParameters(GeocentricToGeographic.NAME));
step.getOrCreate(MapProjection.SEMI_MAJOR).setValue(pv.doubleValue(GeocentricAffineBetweenGeographic.TGT_SEMI_MAJOR));
step.getOrCreate(MapProjection.SEMI_MINOR).setValue(pv.doubleValue(GeocentricAffineBetweenGeographic.TGT_SEMI_MINOR));
MathTransform toGeographic = factory.createParameterizedTransform(step);
assertEquals("sourceDimensions", 3, toGeographic.getSourceDimensions());
assertEquals("targetDimensions", 3, toGeographic.getTargetDimensions());
toGeographic = factory.createConcatenatedTransform(toGeographic, reduce);
assertEquals("sourceDimensions", 3, toGeographic.getSourceDimensions());
assertEquals("targetDimensions", 2, toGeographic.getTargetDimensions());
/*
* The Geocentric → Affine → Geographic chain.
*/
return factory.createConcatenatedTransform(toGeocentric, factory.createConcatenatedTransform(affine, toGeographic));
}
use of org.opengis.util.FactoryException in project sis by apache.
the class TransformSeparator method filterSourceDimensions.
/**
* Creates a transform for the same mathematic than the given {@code step}
* but expecting only the given dimensions as inputs.
* This method is invoked by {@link #separate()} when user-specified source dimensions need to be taken in account.
* The given {@code step} and {@code dimensions} are typically the values of
* {@link #transform} and {@link #sourceDimensions} fields respectively, but not necessarily.
* In particular those arguments will differ when this method is invoked recursively for processing
* concatenated or {@linkplain PassThroughTransform#getSubTransform() sub-transforms}.
*
* <p>Subclasses can override this method if they need to handle some {@code MathTransform} implementations
* in a special way. However all implementations of this method shall obey to the following contract:</p>
* <ul class="verbose">
* <li>{@link #sourceDimensions} and {@link #targetDimensions} should not be assumed accurate
* since they may be temporarily outdated or modified during recursive calls to this method.</li>
* <li>{@link #sourceDimensions} should not be modified by this method.</li>
* <li>{@link #targetDimensions} <strong>must</strong> be <em>overwritten</em> (not updated) by this method to the
* sequence of all target dimensions of {@code step} that are also target dimensions of the returned transform.
* The indices shall be in strictly increasing order from 0 inclusive to
* {@code step.getTargetDimensions()} exclusive.</li>
* </ul>
*
* @param step the transform for which to retain only a subset of the source dimensions.
* @param dimensions indices of the source dimensions of {@code step} to retain.
* @return a transform expecting only the given source dimensions.
* @throws FactoryException if the given transform is not separable.
*/
@SuppressWarnings("AssignmentToCollectionOrArrayFieldFromParameter")
protected MathTransform filterSourceDimensions(final MathTransform step, final int[] dimensions) throws FactoryException {
if (dimensions.length == 0) {
return IdentityTransform.create(0);
}
final int numSrc = step.getSourceDimensions();
final int numTgt = step.getTargetDimensions();
final int lower = dimensions[0];
final int upper = dimensions[dimensions.length - 1] + 1;
if (lower == 0 && upper == numSrc && dimensions.length == numSrc) {
targetDimensions = series(0, numTgt);
return step;
}
if (step.isIdentity()) {
targetDimensions = dimensions;
return IdentityTransform.create(dimensions.length);
}
if (step instanceof ConcatenatedTransform) {
final ConcatenatedTransform ctr = (ConcatenatedTransform) step;
final MathTransform step1 = filterSourceDimensions(ctr.transform1, dimensions);
final MathTransform step2 = filterSourceDimensions(ctr.transform2, targetDimensions);
return factory.createConcatenatedTransform(step1, step2);
// Keep the 'targetDimensions' computed by the last step.
}
/*
* Special case for the passthrough transform: if at least one input dimension belong to the pass-
* through sub-transform, then invoke this method recursively for the sub-transform dimensions.
*/
if (step instanceof PassThroughTransform) {
final PassThroughTransform passThrough = (PassThroughTransform) step;
final int numSubSrc = passThrough.subTransform.getSourceDimensions();
final int numNewDim = passThrough.subTransform.getTargetDimensions() - numSubSrc;
final int subLower = passThrough.firstAffectedOrdinate;
final int subUpper = subLower + numSubSrc;
int[] subDimensions = new int[dimensions.length];
targetDimensions = null;
int n = 0;
for (int dim : dimensions) {
if (dim >= subLower) {
if (dim < subUpper) {
// Dimension n belong to the subtransform.
subDimensions[n++] = dim - subLower;
continue;
}
dim += numNewDim;
}
/*
* Dimension n belong to heading or trailing dimensions.
* Passthrough, after adjustment for trailing dimensions.
*/
targetDimensions = insert(targetDimensions, dim);
}
subDimensions = ArraysExt.resize(subDimensions, n);
/*
* If no source dimension belong to the sub-transform, then all source dimensions are heading or
* trailing dimensions. A passthrough transform without its sub-transform is an identity transform.
*/
if (n == 0) {
return IdentityTransform.create(dimensions.length);
}
/*
* There is at least one dimension to separate in the sub-transform. Perform this separation and get
* the list of target dimensions. We need to offset the target dimensions by the amount of leading
* dimensions once the separation is done, in order to translate from the sub-transform's dimension
* numbering to the transform's numbering.
*/
int[] target = targetDimensions;
final MathTransform subTransform = filterSourceDimensions(passThrough.subTransform, subDimensions);
for (final int dim : targetDimensions) {
target = insert(target, dim + subLower);
}
targetDimensions = target;
/*
* If all source dimensions not in the sub-transform are consecutive numbers, we can use our passthrough
* transform implementation. The "consecutive numbers" requirement (expressed in the 'if' statement below)
* is a consequence of a limitation in our current implementation: our current passthrough transform does
* not accept arbitrary index for modified ordinates.
*/
if (containsAll(dimensions, lower, subLower) && containsAll(dimensions, subUpper, upper)) {
return factory.createPassThroughTransform(subLower - lower, subTransform, Math.max(0, upper - subUpper));
}
}
/*
* If the transform is affine (or at least projective), express the transform as a matrix. Then, select
* target dimensions that depend only on specified source dimensions. If a target dimension depends on
* at least one discarded source dimension, then that output dimension will be discarded as well.
*/
final Matrix matrix = MathTransforms.getMatrix(step);
if (matrix != null) {
targetDimensions = null;
int startOfRow = 0;
boolean isLastRowAccepted = false;
final int numFilteredColumns = (dimensions.length + 1);
double[] elements = new double[(numTgt + 1) * numFilteredColumns];
reduce: for (int j = 0; j <= numTgt; j++) {
/*
* For each target dimension (i.e. a matrix row), find the matrix elements (excluding translation
* terms in the last column) for each source dimension to be kept. If a dependancy to at least one
* discarded input dimension is found, then the whole output dimension is discarded.
*/
int filteredColumn = 0;
for (int i = 0; i < numSrc; i++) {
final double element = matrix.getElement(j, i);
if (filteredColumn < dimensions.length && dimensions[filteredColumn] == i) {
elements[startOfRow + filteredColumn++] = element;
} else if (element != 0) {
/*
* Output dimension 'j' depends on one of discarded input dimension 'i'.
* The whole row will be discarded.
*/
continue reduce;
}
}
// Copy the translation term.
elements[startOfRow + filteredColumn++] = matrix.getElement(j, numSrc);
// We should have used all values in the 'dimensions' array.
assert filteredColumn == numFilteredColumns : filteredColumn;
startOfRow += numFilteredColumns;
if (j == numTgt) {
/*
* In an affine transform, the last row is usually [0 0 0 … 1].
* This is not a real dimension, but nevertheless mandatory.
*/
isLastRowAccepted = true;
} else {
targetDimensions = insert(targetDimensions, j);
}
}
if (isLastRowAccepted) {
elements = ArraysExt.resize(elements, startOfRow);
return factory.createAffineTransform(Matrices.create(startOfRow / numFilteredColumns, numFilteredColumns, elements));
}
/*
* In an affine transform, the last row is not supposed to have dependency to any source dimension.
* But if we reach this point, our matrix has such dependencies.
*/
}
throw new FactoryException(Resources.format(Resources.Keys.NotAnAffineTransform));
}
use of org.opengis.util.FactoryException in project sis by apache.
the class EPSGFactoryTest method testDeprecatedCoordinateSystems.
/**
* Tests creation of deprecated coordinate systems.
*
* @throws FactoryException if an error occurred while querying the factory.
*/
@Test
public void testDeprecatedCoordinateSystems() throws FactoryException {
final EPSGFactory factory = TestFactorySource.factory;
assumeNotNull(factory);
for (final Map.Entry<Integer, Integer> entry : EPSGDataAccess.deprecatedCS().entrySet()) {
final CoordinateSystem expected = factory.createEllipsoidalCS(entry.getValue().toString());
loggings.assertNoUnexpectedLog();
final String code = entry.getKey().toString();
final CoordinateSystem deprecated;
try {
deprecated = factory.createEllipsoidalCS(code);
} catch (FactoryException e) {
final String m = e.getMessage();
if (m.contains("9115") || m.contains("9116") || m.contains("9117") || m.contains("9118") || m.contains("9119") || m.contains("9120")) {
// Unit "9116" to "9120" are known to be unsupported.
continue;
}
throw e;
}
loggings.assertNextLogContains(code);
final int dimension = expected.getDimension();
assertEquals("dimension", dimension, deprecated.getDimension());
for (int i = 0; i < dimension; i++) {
final CoordinateSystemAxis ref = expected.getAxis(i);
final CoordinateSystemAxis axis = deprecated.getAxis(i);
assertEquals("name", ref.getName(), axis.getName());
assertEquals("alias", ref.getAlias(), axis.getAlias());
assertEquals("direction", ref.getDirection(), axis.getDirection());
assertEquals("rangeMeaning", ref.getRangeMeaning(), axis.getRangeMeaning());
assertEquals("unit", ref.getUnit().getSystemUnit(), axis.getUnit().getSystemUnit());
}
}
}
use of org.opengis.util.FactoryException in project sis by apache.
the class DefaultVerticalExtent method intersect.
/**
* Sets this vertical extent to the intersection of this extent with the specified one.
* The {@linkplain org.apache.sis.referencing.crs.DefaultVerticalCRS#getDatum() vertical datum}
* must be the same (ignoring metadata) for both extents; this method does not perform datum shift.
* However this method can perform unit conversions.
*
* <p>If there is no intersection between the two extents, then this method sets both minimum and
* maximum values to {@linkplain Double#NaN}. If either this extent or the specified extent has NaN
* bounds, then the corresponding bounds of the intersection result will also be NaN.</p>
*
* @param other the vertical extent to intersect with this extent.
* @throws IllegalArgumentException if the two extents do not use the same datum, ignoring metadata.
*
* @see Extents#intersection(VerticalExtent, VerticalExtent)
* @see org.apache.sis.geometry.GeneralEnvelope#intersect(Envelope)
*
* @since 0.8
*/
public void intersect(final VerticalExtent other) throws IllegalArgumentException {
checkWritePermission();
ArgumentChecks.ensureNonNull("other", other);
Double min = other.getMinimumValue();
Double max = other.getMaximumValue();
try {
final MathTransform1D cv = getConversionFrom(other.getVerticalCRS());
if (isReversing(cv, min, max)) {
Double tmp = min;
min = max;
max = tmp;
}
/*
* If minimumValue is NaN, keep it unchanged (because x > minimumValue is false)
* in order to preserve the NilReason. Conversely if min is NaN, then we want to
* take it without conversion for preserving its NilReason.
*/
if (min != null) {
if (minimumValue == null || min.isNaN() || (min = convert(cv, min)) > minimumValue) {
minimumValue = min;
}
}
if (max != null) {
if (maximumValue == null || max.isNaN() || (max = convert(cv, max)) < maximumValue) {
maximumValue = max;
}
}
} catch (UnsupportedOperationException | FactoryException | ClassCastException | TransformException e) {
throw new IllegalArgumentException(Errors.format(Errors.Keys.IncompatiblePropertyValue_1, "verticalCRS"), e);
}
if (minimumValue != null && maximumValue != null && minimumValue > maximumValue) {
minimumValue = maximumValue = NilReason.MISSING.createNilObject(Double.class);
}
}
use of org.opengis.util.FactoryException in project sis by apache.
the class CoordinateSystemTransform method create.
/**
* Implementation of {@link DefaultMathTransformFactory#createCoordinateSystemChange(CoordinateSystem,
* CoordinateSystem, Ellipsoid)}, defined here for reducing the {@code DefaultMathTransformFactory}
* weight in the common case where the conversions handled by this class are not needed.
*/
static MathTransform create(final MathTransformFactory factory, final CoordinateSystem source, final CoordinateSystem target) throws FactoryException {
int passthrough = 0;
CoordinateSystemTransform kernel = null;
if (source instanceof CartesianCS) {
if (target instanceof SphericalCS) {
kernel = CartesianToSpherical.INSTANCE;
} else if (target instanceof PolarCS) {
kernel = CartesianToPolar.INSTANCE;
} else if (target instanceof CylindricalCS) {
kernel = CartesianToPolar.INSTANCE;
passthrough = 1;
}
} else if (target instanceof CartesianCS) {
if (source instanceof SphericalCS) {
kernel = SphericalToCartesian.INSTANCE;
} else if (source instanceof PolarCS) {
kernel = PolarToCartesian.INSTANCE;
} else if (source instanceof CylindricalCS) {
kernel = PolarToCartesian.INSTANCE;
passthrough = 1;
}
}
Exception cause = null;
try {
if (kernel == null) {
return factory.createAffineTransform(CoordinateSystems.swapAndScaleAxes(source, target));
} else if (source.getDimension() == kernel.getSourceDimensions() + passthrough && target.getDimension() == kernel.getTargetDimensions() + passthrough) {
final MathTransform tr = (passthrough == 0) ? kernel.completeTransform(factory) : kernel.passthrough(factory);
final MathTransform before = factory.createAffineTransform(CoordinateSystems.swapAndScaleAxes(source, CoordinateSystems.replaceAxes(source, AxesConvention.NORMALIZED)));
final MathTransform after = factory.createAffineTransform(CoordinateSystems.swapAndScaleAxes(CoordinateSystems.replaceAxes(target, AxesConvention.NORMALIZED), target));
return factory.createConcatenatedTransform(before, factory.createConcatenatedTransform(tr, after));
}
} catch (IllegalArgumentException | IncommensurableException e) {
cause = e;
}
throw new OperationNotFoundException(Resources.format(Resources.Keys.CoordinateOperationNotFound_2, WKTUtilities.toType(CoordinateSystem.class, source.getClass()), WKTUtilities.toType(CoordinateSystem.class, target.getClass())), cause);
}
Aggregations