use of org.opengis.referencing.cs.CoordinateSystem 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.CoordinateSystem in project sis by apache.
the class CoordinateSystems method swapAndScaleAxes.
/**
* Returns an affine transform between two coordinate systems.
* Only units and axes order (e.g. transforming from
* ({@linkplain AxisDirection#NORTH North}, {@linkplain AxisDirection#WEST West}) to
* ({@linkplain AxisDirection#EAST East}, {@linkplain AxisDirection#NORTH North})
* are taken in account by this method.
*
* <div class="section">Conditions</div>
* The two coordinate systems must implement the same GeoAPI coordinate system interface.
* For example if {@code sourceCS} is a {@link org.opengis.referencing.cs.CartesianCS},
* then {@code targetCS} must be a {@code CartesianCS} too.
*
* <div class="note"><b>Example:</b>
* If coordinates in {@code sourceCS} are (<var>x</var>,<var>y</var>) tuples in metres
* and coordinates in {@code targetCS} are (<var>-y</var>,<var>x</var>) tuples in centimetres,
* then the transformation can be performed as below:
*
* {@preformat math
* ┌ ┐ ┌ ┐ ┌ ┐
* │-y(cm)│ │ 0 -100 0 │ │ x(m)│
* │ x(cm)│ = │ 100 0 0 │ │ y(m)│
* │ 1 │ │ 0 0 1 │ │ 1 │
* └ ┘ └ ┘ └ ┘
* }
* </div>
*
* @param sourceCS the source coordinate system.
* @param targetCS the target coordinate system.
* @return the conversion from {@code sourceCS} to {@code targetCS} as an affine transform.
* Only axis direction and units are taken in account.
* @throws IllegalArgumentException if the CS are not of the same type, or axes do not match.
* @throws IncommensurableException if the units are not compatible, or the conversion is non-linear.
*
* @see Matrices#createTransform(AxisDirection[], AxisDirection[])
*/
@SuppressWarnings("fallthrough")
public static Matrix swapAndScaleAxes(final CoordinateSystem sourceCS, final CoordinateSystem targetCS) throws IllegalArgumentException, IncommensurableException {
ensureNonNull("sourceCS", sourceCS);
ensureNonNull("targetCS", targetCS);
if (!Classes.implementSameInterfaces(sourceCS.getClass(), targetCS.getClass(), CoordinateSystem.class)) {
throw new IllegalArgumentException(Resources.format(Resources.Keys.IncompatibleCoordinateSystemTypes));
}
final AxisDirection[] srcAxes = getAxisDirections(sourceCS);
final AxisDirection[] dstAxes = getAxisDirections(targetCS);
final MatrixSIS matrix = Matrices.createTransform(srcAxes, dstAxes);
assert Arrays.equals(srcAxes, dstAxes) == matrix.isIdentity() : matrix;
/*
* The previous code computed a matrix for swapping axes. Usually, this
* matrix contains only 0 and 1 values with only one "1" value by row.
* For example, the matrix operation for swapping x and y axes is:
* ┌ ┐ ┌ ┐ ┌ ┐
* │y│ │ 0 1 0 │ │x│
* │x│ = │ 1 0 0 │ │y│
* │1│ │ 0 0 1 │ │1│
* └ ┘ └ ┘ └ ┘
* Now, take in account units conversions. Each matrix's element (j,i)
* is multiplied by the conversion factor from sourceCS.getUnit(i) to
* targetCS.getUnit(j). This is an element-by-element multiplication,
* not a matrix multiplication. The last column is processed in a special
* way, since it contains the offset values.
*/
// == sourceCS.getDimension()
final int sourceDim = matrix.getNumCol() - 1;
// == targetCS.getDimension()
final int targetDim = matrix.getNumRow() - 1;
for (int j = 0; j < targetDim; j++) {
final Unit<?> targetUnit = targetCS.getAxis(j).getUnit();
for (int i = 0; i < sourceDim; i++) {
if (matrix.getElement(j, i) == 0) {
// (i.e. axes are orthogonal).
continue;
}
final Unit<?> sourceUnit = sourceCS.getAxis(i).getUnit();
if (Objects.equals(sourceUnit, targetUnit)) {
// between source[i] and target[j].
continue;
}
Number scale = 1;
Number offset = 0;
final Number[] coefficients = Units.coefficients(sourceUnit.getConverterToAny(targetUnit));
switch(coefficients != null ? coefficients.length : -1) {
// Fall through
case 2:
scale = coefficients[1];
// Fall through
case 1:
offset = coefficients[0];
case 0:
break;
default:
throw new IncommensurableException(Resources.format(Resources.Keys.NonLinearUnitConversion_2, sourceUnit, targetUnit));
}
final DoubleDouble element = DoubleDouble.castOrCopy(matrix.getNumber(j, i));
final DoubleDouble r = new DoubleDouble(element);
r.multiply(scale);
matrix.setNumber(j, i, r);
r.setFrom(element);
r.multiply(offset);
r.add(matrix.getNumber(j, sourceDim));
matrix.setNumber(j, sourceDim, r);
}
}
return matrix;
}
use of org.opengis.referencing.cs.CoordinateSystem in project sis by apache.
the class DefaultDerivedCRS method formatTo.
/**
* Formats the inner part of the <cite>Well Known Text</cite> (WKT) representation of this CRS.
*
* @return {@code "Fitted_CS"} (WKT 1) or a type-dependent keyword (WKT 2).
*
* @see <a href="http://docs.opengeospatial.org/is/12-063r5/12-063r5.html#93">WKT 2 specification §15</a>
*/
@Override
protected String formatTo(final Formatter formatter) {
// Gives to users a chance to override.
final Conversion conversion = getConversionFromBase();
if (conversion == null) {
/*
* Should never happen except temporarily at construction time, or if the user invoked the copy
* constructor with an invalid Conversion, or if the user overrides the getConversionFromBase()
* method. Delegates to the super-class method for avoiding a NullPointerException. That method
* returns 'null', which will cause the WKT to be declared invalid.
*/
return super.formatTo(formatter);
}
WKTUtilities.appendName(this, formatter, null);
final Convention convention = formatter.getConvention();
final boolean isWKT1 = (convention.majorVersion() == 1);
/*
* Both WKT 1 and WKT 2 format the base CRS. But WKT 1 formats the MathTransform before the base CRS,
* while WKT 2 formats the conversion method and parameter values after the base CRS.
*/
if (isWKT1) {
MathTransform inverse = conversion.getMathTransform();
try {
inverse = inverse.inverse();
} catch (NoninvertibleTransformException exception) {
formatter.setInvalidWKT(this, exception);
inverse = null;
}
formatter.newLine();
formatter.append(inverse);
}
formatter.newLine();
formatter.append(WKTUtilities.toFormattable(getBaseCRS()));
if (isWKT1) {
return WKTKeywords.Fitted_CS;
} else {
formatter.newLine();
formatter.append(new // Format inside a "DefiningConversion" element.
FormattableObject() {
@Override
protected String formatTo(final Formatter formatter) {
WKTUtilities.appendName(conversion, formatter, null);
formatter.newLine();
formatter.append(DefaultOperationMethod.castOrCopy(conversion.getMethod()));
formatter.newLine();
for (final GeneralParameterValue param : conversion.getParameterValues().values()) {
WKTUtilities.append(param, formatter);
}
return WKTKeywords.DerivingConversion;
}
});
if (convention == Convention.INTERNAL || !isBaseCRS(formatter)) {
final CoordinateSystem cs = getCoordinateSystem();
formatCS(formatter, cs, ReferencingUtilities.getUnit(cs), isWKT1);
}
return keyword(formatter);
}
}
use of org.opengis.referencing.cs.CoordinateSystem in project sis by apache.
the class ReferencingFunctions method getAxis.
/**
* Returns the axis name and units for the specified dimension in a coordinate reference system or coordinate system.
* This method returns a short axis name as used in Well Known Text (WKT) format, for example <cite>"Latitude"</cite>
* instead of <cite>"Geodetic latitude"</cite>.
*
* @param codeOrPath the code allocated by an authority, or the path to a file.
* @param dimension the dimension (1, 2, …).
* @return the name of the requested axis.
*/
@Override
public String getAxis(final String codeOrPath, final int dimension) {
final CacheKey<String> key = new CacheKey<>(String.class, codeOrPath, dimension, null);
String name = key.peek();
if (name == null) {
final Cache.Handler<String> handler = key.lock();
try {
name = handler.peek();
if (name == null) {
final IdentifiedObject object;
try {
object = getIdentifiedObject(codeOrPath, null);
} catch (Exception exception) {
return getLocalizedMessage(exception);
}
CoordinateSystem cs = null;
final CoordinateSystemAxis axis;
if (object instanceof CoordinateSystemAxis) {
axis = (CoordinateSystemAxis) object;
} else {
if (object instanceof CoordinateReferenceSystem) {
cs = ((CoordinateReferenceSystem) object).getCoordinateSystem();
} else if (object instanceof CoordinateSystem) {
cs = (CoordinateSystem) object;
} else {
final Class<?> actual;
if (object instanceof AbstractIdentifiedObject) {
actual = ((AbstractIdentifiedObject) object).getInterface();
} else {
actual = Classes.getClass(object);
}
return Errors.getResources(getJavaLocale()).getString(Errors.Keys.UnexpectedTypeForReference_3, codeOrPath, CoordinateReferenceSystem.class, actual);
}
if (dimension >= 1 && dimension <= cs.getDimension()) {
axis = cs.getAxis(dimension - 1);
} else {
return Errors.getResources(getJavaLocale()).getString(Errors.Keys.IndexOutOfBounds_1, dimension);
}
}
final String unit = axis.getUnit().toString();
name = Transliterator.DEFAULT.toShortAxisName(cs, axis.getDirection(), axis.getName().getCode());
if (unit != null && !unit.isEmpty()) {
name = name + " (" + unit + ')';
}
}
} finally {
handler.putAndUnlock(name);
}
}
return name;
}
use of org.opengis.referencing.cs.CoordinateSystem 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;
}
Aggregations