use of org.opengis.referencing.cs.CoordinateSystem in project sis by apache.
the class DefaultCoordinateSystemAxis method formatTo.
/**
* Formats this axis as a <cite>Well Known Text</cite> {@code Axis[…]} element.
*
* <div class="section">Constraints for WKT validity</div>
* The ISO 19162 specification puts many constraints on axis names, abbreviations and directions allowed in WKT.
* Most of those constraints are inherited from ISO 19111 — see {@link CoordinateSystemAxis} javadoc for some of
* those. The current Apache SIS implementation does not verify whether this axis name and abbreviation are
* compliant; we assume that the user created a valid axis.
* The only actions (derived from ISO 19162 rules) taken by this method (by default) are:
*
* <ul>
* <li>Replace <cite>“Geodetic latitude”</cite> and <cite>“Geodetic longitude”</cite> names (case insensitive)
* by <cite>“latitude”</cite> and <cite>“longitude”</cite> respectively.</li>
* <li>For latitude and longitude axes, replace “φ” and “λ” abbreviations by <var>“B”</var> and <var>“L”</var>
* respectively (from German “Breite” and “Länge”, used in academic texts worldwide).
* Note that <var>“L”</var> is also the transliteration of Greek letter “lambda” (λ).</li>
* <li>In {@link SphericalCS}, replace “φ” and “θ” abbreviations by <var>“U”</var> and <var>“V”</var> respectively.</li>
* <li>In {@link PolarCS}, replace “θ” abbreviation by <var>“U”</var>.</li>
* </ul>
*
* The above-cited replacements of name and Greek letters can be controlled by a call to
* {@link org.apache.sis.io.wkt.WKTFormat#setTransliterator(Transliterator)}.
*
* @return {@code "Axis"}.
*
* @see <a href="http://docs.opengeospatial.org/is/12-063r5/12-063r5.html#39">WKT 2 specification §7.5.3</a>
*/
@Override
protected String formatTo(final Formatter formatter) {
final Convention convention = formatter.getConvention();
final boolean isWKT1 = (convention.majorVersion() == 1);
final boolean isInternal = (convention == Convention.INTERNAL);
final CoordinateSystem cs = getEnclosingCS(formatter);
AxisDirection dir = getDirection();
String name = IdentifiedObjects.getName(this, formatter.getNameAuthority());
if (name == null) {
name = IdentifiedObjects.getName(this, null);
}
if (name != null && !isInternal) {
final String old = name;
name = formatter.getTransliterator().toShortAxisName(cs, dir, name);
if (name == null && isWKT1) {
// WKT 1 does not allow omission of name.
name = old;
}
}
/*
* ISO 19162:2015 §7.5.3 suggests to put abbreviation in parentheses, e.g. "Easting (x)".
* The specification also suggests to write only the abbreviation (e.g. "(X)") in the
* special case of Geocentric axis, and disallows Greek letters.
*/
if (!isWKT1) {
final String a = formatter.getTransliterator().toLatinAbbreviation(cs, dir, getAbbreviation());
if (a != null && !a.equals(name)) {
final StringBuilder buffer = new StringBuilder();
if (name != null) {
buffer.append(name).append(' ');
}
name = buffer.append('(').append(a).append(')').toString();
}
}
formatter.append(name, ElementKind.AXIS);
/*
* Format the axis direction, optionally followed by a MERIDIAN[…] element
* if the direction is of the kind "South along 90°N" for instance.
*/
DirectionAlongMeridian meridian = null;
if (AxisDirections.isUserDefined(dir)) {
meridian = DirectionAlongMeridian.parse(dir);
if (meridian != null) {
dir = meridian.baseDirection;
if (isWKT1) {
formatter.setInvalidWKT(this, null);
}
}
}
formatter.append(dir);
formatter.append(meridian);
/*
* Formats the axis unit only if the enclosing CRS element does not provide one.
* If the enclosing CRS provided a contextual unit, then it is assumed to apply
* to all axes (we do not verify).
*/
if (!isWKT1) {
if (convention == Convention.WKT2 && cs != null) {
final Order order = Order.create(cs, this);
if (order != null) {
formatter.append(order);
} else {
formatter.setInvalidWKT(cs, null);
}
}
if (!formatter.hasContextualUnit(1)) {
formatter.append(getUnit());
}
}
return WKTKeywords.Axis;
}
use of org.opengis.referencing.cs.CoordinateSystem in project sis by apache.
the class EllipsoidalHeightCombiner method createCompoundCRS.
/**
* Creates a compound CRS, but we special processing for (two-dimensional Geographic + ellipsoidal heights) tupples.
* If any such tupple is found, a three-dimensional geographic CRS is created instead than the compound CRS.
*
* @param properties name and other properties to give to the new object.
* @param components ordered array of {@code CoordinateReferenceSystem} objects.
* @return the coordinate reference system for the given properties.
* @throws FactoryException if the object creation failed.
*/
public final CoordinateReferenceSystem createCompoundCRS(final Map<String, ?> properties, CoordinateReferenceSystem... components) throws FactoryException {
for (int i = 0; i < components.length; i++) {
final CoordinateReferenceSystem vertical = components[i];
if (vertical instanceof VerticalCRS) {
final VerticalDatum datum = ((VerticalCRS) vertical).getDatum();
if (datum != null && datum.getVerticalDatumType() == VerticalDatumTypes.ELLIPSOIDAL) {
int axisPosition = 0;
CoordinateSystem cs = null;
CoordinateReferenceSystem crs = null;
if (i == 0 || (cs = getCsIfHorizontal2D(crs = components[i - 1])) == null) {
/*
* GeographicCRS are normally before VerticalCRS. But Apache SIS is tolerant to the
* opposite order (note however that such ordering is illegal according ISO 19162).
*/
if (i + 1 >= components.length || (cs = getCsIfHorizontal2D(crs = components[i + 1])) == null) {
continue;
}
axisPosition = 1;
}
/*
* At this point we have the horizontal and vertical components. The horizontal component
* begins at 'axisPosition', which is almost always zero. Create the three-dimensional CRS.
* If the result is the CRS to be returned directly by this method (components.length == 2),
* use the properties given in argument. Otherwise we need to use other properties; current
* implementation recycles the properties of the existing two-dimensional CRS.
*/
final CoordinateSystemAxis[] axes = new CoordinateSystemAxis[3];
axes[axisPosition++] = cs.getAxis(0);
axes[axisPosition++] = cs.getAxis(1);
axes[axisPosition %= 3] = vertical.getCoordinateSystem().getAxis(0);
final ReferencingServices referencing = ReferencingServices.getInstance();
final Map<String, ?> csProps = referencing.getProperties(cs, false);
final Map<String, ?> crsProps = (components.length == 2) ? properties : referencing.getProperties(crs, false);
if (crs instanceof GeodeticCRS) {
initialize(CS | CRS);
cs = csFactory.createEllipsoidalCS(csProps, axes[0], axes[1], axes[2]);
crs = crsFactory.createGeographicCRS(crsProps, ((GeodeticCRS) crs).getDatum(), (EllipsoidalCS) cs);
} else {
initialize(CS | CRS | OPERATION);
final ProjectedCRS proj = (ProjectedCRS) crs;
GeographicCRS base = proj.getBaseCRS();
if (base.getCoordinateSystem().getDimension() == 2) {
base = (GeographicCRS) createCompoundCRS(referencing.getProperties(base, false), base, vertical);
}
/*
* In Apache SIS implementation, the Conversion contains the source and target CRS together with
* a MathTransform2D. We need to recreate the same conversion, but without CRS and MathTransform
* for letting SIS create or associate new ones, which will be three-dimensional now.
*/
Conversion fromBase = proj.getConversionFromBase();
fromBase = opFactory.createDefiningConversion(referencing.getProperties(fromBase, true), fromBase.getMethod(), fromBase.getParameterValues());
cs = csFactory.createCartesianCS(csProps, axes[0], axes[1], axes[2]);
crs = crsFactory.createProjectedCRS(crsProps, base, fromBase, (CartesianCS) cs);
}
/*
* Remove the VerticalCRS and store the three-dimensional GeographicCRS in place of the previous
* two-dimensional GeographicCRS. Then let the loop continues in case there is other CRS to merge
* (should never happen, but we are paranoiac).
*/
components = ArraysExt.remove(components, i, 1);
// GeographicCRS before VerticalCRS (usual case).
if (axisPosition != 0)
i--;
components[i] = crs;
}
}
}
switch(components.length) {
case 0:
return null;
case 1:
return components[0];
default:
initialize(CRS);
return crsFactory.createCompoundCRS(properties, components);
}
}
use of org.opengis.referencing.cs.CoordinateSystem in project sis by apache.
the class ServicesForMetadata method setGeographicExtent.
/**
* Implementation of the public {@code setBounds(…, DefaultGeographicBoundingBox, …)} methods for
* the horizontal extent. If the {@code crs} argument is null, then it is caller's responsibility
* to ensure that the given envelope is two-dimensional.
*
* @param envelope the source envelope.
* @param target the target bounding box.
* @param crs the envelope CRS, or {@code null} if unknown.
* @param normalizedCRS the horizontal component of the given CRS, or null if the {@code crs} argument is null.
* @throws TransformException if the given envelope can not be transformed.
*/
private void setGeographicExtent(Envelope envelope, final DefaultGeographicBoundingBox target, final CoordinateReferenceSystem crs, final GeographicCRS normalizedCRS) throws TransformException {
if (normalizedCRS != null) {
// No need to check for dimension, since GeodeticCRS can not have less than 2.
final CoordinateSystem cs1 = crs.getCoordinateSystem();
final CoordinateSystem cs2 = normalizedCRS.getCoordinateSystem();
if (!Utilities.equalsIgnoreMetadata(cs2.getAxis(0), cs1.getAxis(0)) || !Utilities.equalsIgnoreMetadata(cs2.getAxis(1), cs1.getAxis(1))) {
final CoordinateOperation operation;
final CoordinateOperationFactory factory = CoordinateOperations.factory();
try {
operation = factory.createOperation(crs, normalizedCRS);
} catch (FactoryException e) {
throw new TransformException(Resources.format(Resources.Keys.CanNotTransformEnvelopeToGeodetic), e);
}
envelope = Envelopes.transform(operation, envelope);
}
}
/*
* At this point, the envelope should use (longitude, latitude) coordinates in degrees.
* However the prime meridian is not necessarily Greenwich.
*/
double westBoundLongitude = envelope.getMinimum(0);
double eastBoundLongitude = envelope.getMaximum(0);
double southBoundLatitude = envelope.getMinimum(1);
double northBoundLatitude = envelope.getMaximum(1);
if (normalizedCRS != null) {
final double rotation = CRS.getGreenwichLongitude(normalizedCRS);
westBoundLongitude += rotation;
eastBoundLongitude += rotation;
}
target.setBounds(westBoundLongitude, eastBoundLongitude, southBoundLatitude, northBoundLatitude);
target.setInclusion(Boolean.TRUE);
}
use of org.opengis.referencing.cs.CoordinateSystem in project sis by apache.
the class CommonCRSTest method testNormalizedGeographic.
/**
* Tests the {@link CommonCRS#normalizedGeographic()} method.
*/
@Test
@DependsOnMethod("testGeographic")
public void testNormalizedGeographic() {
final GeographicCRS geographic = CommonCRS.WGS84.geographic();
final GeographicCRS normalized = CommonCRS.WGS84.normalizedGeographic();
Validators.validate(normalized);
assertSame(geographic.getDatum(), normalized.getDatum());
final CoordinateSystem φλ = geographic.getCoordinateSystem();
final CoordinateSystem λφ = normalized.getCoordinateSystem();
assertSame("Longitude", φλ.getAxis(1), λφ.getAxis(0));
assertSame("Latitude", φλ.getAxis(0), λφ.getAxis(1));
assertSame("Cached value", normalized, CommonCRS.WGS84.normalizedGeographic());
}
use of org.opengis.referencing.cs.CoordinateSystem in project sis by apache.
the class DefaultEngineeringCRSTest method testCartesianXML.
/**
* Tests XML (un)marshalling of an engineering CRS using a Cartesian CS.
*
* @throws JAXBException if an error occurred during (un)marshalling.
*/
@Test
public void testCartesianXML() throws JAXBException {
final String xml = marshal(createCartesian());
assertXmlEquals("<gml:EngineeringCRS xmlns:gml=\"" + Namespaces.GML + "\">\n" + " <gml:name>A construction site CRS</gml:name>\n" + " <gml:cartesianCS gml:id=\"Cartesian2D\">\n" + " <gml:name>Cartesian 2D</gml:name>\n" + " <gml:axis>\n" + " <gml:CoordinateSystemAxis uom=\"urn:ogc:def:uom:EPSG::9001\" gml:id=\"x\">\n" + " <gml:name>x</gml:name>\n" + " <gml:axisAbbrev>x</gml:axisAbbrev>\n" + " <gml:axisDirection codeSpace=\"EPSG\">east</gml:axisDirection>\n" + " </gml:CoordinateSystemAxis>\n" + " </gml:axis>\n" + " <gml:axis>\n" + " <gml:CoordinateSystemAxis uom=\"urn:ogc:def:uom:EPSG::9001\" gml:id=\"y\">\n" + " <gml:name>y</gml:name>\n" + " <gml:axisAbbrev>y</gml:axisAbbrev>\n" + " <gml:axisDirection codeSpace=\"EPSG\">north</gml:axisDirection>\n" + " </gml:CoordinateSystemAxis>\n" + " </gml:axis>\n" + " </gml:cartesianCS>\n" + " <gml:engineeringDatum>\n" + " <gml:EngineeringDatum gml:id=\"P1\">\n" + " <gml:name>P1</gml:name>\n" + " </gml:EngineeringDatum>\n" + " </gml:engineeringDatum>\n" + "</gml:EngineeringCRS>", xml, "xmlns:*");
final DefaultEngineeringCRS crs = unmarshal(DefaultEngineeringCRS.class, xml);
assertEquals("name", "A construction site CRS", crs.getName().getCode());
assertEquals("datum.name", "P1", crs.getDatum().getName().getCode());
final CoordinateSystem cs = crs.getCoordinateSystem();
assertInstanceOf("coordinateSystem", CartesianCS.class, cs);
assertEquals("cs.name", "Cartesian 2D", cs.getName().getCode());
assertEquals("cs.dimension", 2, cs.getDimension());
assertAxisDirectionsEqual("cartesianCS", cs, AxisDirection.EAST, AxisDirection.NORTH);
assertEquals("cs.axis[0].name", "x", cs.getAxis(0).getName().getCode());
assertEquals("cs.axis[1].name", "y", cs.getAxis(1).getName().getCode());
}
Aggregations