use of org.opengis.referencing.cs.EllipsoidalCS in project sis by apache.
the class CRS method horizontalCode.
/**
* If the given CRS would quality as horizontal except for its number of dimensions, returns that number.
* Otherwise returns 0. The number of dimensions can only be 2 or 3.
*/
private static int horizontalCode(final CoordinateReferenceSystem crs) {
/*
* In order to determine if the CRS is geographic, checking the CoordinateSystem type is more reliable
* then checking if the CRS implements the GeographicCRS interface. This is because the GeographicCRS
* type did not existed in ISO 19111:2007, so a CRS could be standard-compliant without implementing
* the GeographicCRS interface.
*/
boolean isEngineering = false;
final boolean isGeodetic = (crs instanceof GeodeticCRS);
if (isGeodetic || crs instanceof ProjectedCRS || (isEngineering = (crs instanceof EngineeringCRS))) {
final CoordinateSystem cs = crs.getCoordinateSystem();
final int dim = cs.getDimension();
if ((dim & ~1) == 2 && (!isGeodetic || (cs instanceof EllipsoidalCS))) {
if (isEngineering) {
int n = 0;
for (int i = 0; i < dim; i++) {
if (AxisDirections.isCompass(cs.getAxis(i).getDirection()))
n++;
}
// If we don't have exactly 2 east, north, etc. directions, consider as non-horizontal.
if (n != 2)
return 0;
}
return dim;
}
}
return 0;
}
use of org.opengis.referencing.cs.EllipsoidalCS in project sis by apache.
the class SubTypes method castOrCopy.
/**
* Returns a SIS implementation for the given coordinate reference system.
*
* @see AbstractCRS#castOrCopy(CoordinateReferenceSystem)
*/
static AbstractCRS castOrCopy(final CoordinateReferenceSystem object) {
if (object instanceof DerivedCRS) {
return DefaultDerivedCRS.castOrCopy((DerivedCRS) object);
}
if (object instanceof ProjectedCRS) {
return DefaultProjectedCRS.castOrCopy((ProjectedCRS) object);
}
if (object instanceof GeodeticCRS) {
if (object instanceof GeographicCRS) {
return DefaultGeographicCRS.castOrCopy((GeographicCRS) object);
}
if (object instanceof GeocentricCRS) {
return DefaultGeocentricCRS.castOrCopy((GeocentricCRS) object);
}
/*
* The GeographicCRS and GeocentricCRS types are not part of ISO 19111.
* ISO uses a single type, GeodeticCRS, for both of them and infer the
* geographic or geocentric type from the coordinate system. We do this
* check here for instantiating the most appropriate SIS type, but only
* if we need to create a new object anyway (see below for rational).
*/
if (object instanceof DefaultGeodeticCRS) {
/*
* Result of XML unmarshalling — keep as-is. We avoid creating a new object because it
* would break object identities specified in GML document by the xlink:href attribute.
* However we may revisit this policy in the future. See SC_CRS.setElement(AbstractCRS).
*/
return (DefaultGeodeticCRS) object;
}
final Map<String, ?> properties = IdentifiedObjects.getProperties(object);
final GeodeticDatum datum = ((GeodeticCRS) object).getDatum();
final CoordinateSystem cs = object.getCoordinateSystem();
if (cs instanceof EllipsoidalCS) {
return new DefaultGeographicCRS(properties, datum, (EllipsoidalCS) cs);
}
if (cs instanceof SphericalCS) {
return new DefaultGeocentricCRS(properties, datum, (SphericalCS) cs);
}
if (cs instanceof CartesianCS) {
return new DefaultGeocentricCRS(properties, datum, (CartesianCS) cs);
}
}
if (object instanceof VerticalCRS) {
return DefaultVerticalCRS.castOrCopy((VerticalCRS) object);
}
if (object instanceof TemporalCRS) {
return DefaultTemporalCRS.castOrCopy((TemporalCRS) object);
}
if (object instanceof EngineeringCRS) {
return DefaultEngineeringCRS.castOrCopy((EngineeringCRS) object);
}
if (object instanceof ImageCRS) {
return DefaultImageCRS.castOrCopy((ImageCRS) object);
}
if (object instanceof CompoundCRS) {
return DefaultCompoundCRS.castOrCopy((CompoundCRS) object);
}
/*
* Intentionally check for AbstractCRS after the interfaces because user may have defined his own
* subclass implementing the interface. If we were checking for AbstractCRS before the interfaces,
* the returned instance could have been a user subclass without the JAXB annotations required
* for XML marshalling.
*/
if (object == null || object instanceof AbstractCRS) {
return (AbstractCRS) object;
}
return new AbstractCRS(object);
}
use of org.opengis.referencing.cs.EllipsoidalCS in project sis by apache.
the class CRSPair method label.
/**
* Returns the name of the GeoAPI interface implemented by the specified object. In the GeographicCRS
* or EllipsoidalCS cases, the trailing CRS or CS suffix is replaced by the number of dimensions
* (e.g. "Geographic3D").
*/
static String label(final IdentifiedObject object) {
if (object == null) {
return null;
}
Class<? extends IdentifiedObject> type;
if (object instanceof AbstractIdentifiedObject) {
type = ((AbstractIdentifiedObject) object).getInterface();
} else {
type = Classes.getLeafInterfaces(object.getClass(), IdentifiedObject.class)[0];
}
String suffix, label = Classes.getShortName(type);
if (label.endsWith((suffix = "CRS")) || label.endsWith(suffix = "CS")) {
Object cs = object;
if (object instanceof CoordinateReferenceSystem) {
cs = ((CoordinateReferenceSystem) object).getCoordinateSystem();
}
if (cs instanceof EllipsoidalCS) {
final StringBuilder sb = new StringBuilder(label);
sb.setLength(label.length() - suffix.length());
label = sb.append(((CoordinateSystem) cs).getDimension()).append('D').toString();
}
}
String name = IdentifiedObjects.getName(object, null);
if (name != null) {
// Arbitrary length threshold.
int i = 30;
if (name.length() >= i) {
while (i > 15) {
// Arbitrary minimal length.
final int c = name.codePointBefore(i);
if (Character.isSpaceChar(c))
break;
i -= Character.charCount(c);
}
name = CharSequences.trimWhitespaces(name, 0, i).toString() + '…';
}
label = label + "[“" + name + "”]";
}
return label;
}
use of org.opengis.referencing.cs.EllipsoidalCS 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;
}
use of org.opengis.referencing.cs.EllipsoidalCS 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);
}
Aggregations