Search in sources :

Example 1 with Projection

use of org.opengis.referencing.operation.Projection in project sis by apache.

the class DefaultOperationMethod method formatTo.

/**
 * Formats this operation as a <cite>Well Known Text</cite> {@code Method[…]} element.
 *
 * @return {@code "Method"} (WKT 2) or {@code "Projection"} (WKT 1).
 *
 * @see <a href="http://docs.opengeospatial.org/is/12-063r5/12-063r5.html#118">WKT 2 specification §17.2.3</a>
 */
@Override
protected String formatTo(final Formatter formatter) {
    final boolean isWKT1 = formatter.getConvention().majorVersion() == 1;
    /*
         * The next few lines below are basically a copy of the work done by super.formatTo(formatter),
         * which search for the name to write inside METHOD["name"]. The difference is in the fallback
         * executed if we do not find a name for the given authority.
         */
    final Citation authority = formatter.getNameAuthority();
    String name = IdentifiedObjects.getName(this, authority);
    ElementKind kind = ElementKind.METHOD;
    if (name == null) {
        /*
             * No name found for the given authority. We may use the primary name as a fallback.
             * But before doing that, maybe we can find the name that we are looking for in the
             * hard-coded values in the 'org.apache.sis.internal.referencing.provider' package.
             * The typical use case is when this DefaultOperationMethod has been instantiated
             * by the EPSG factory using only the information found in the EPSG database.
             *
             * We can find the hard-coded names by looking at the ParameterDescriptorGroup of the
             * enclosing ProjectedCRS or DerivedCRS. This is because that parameter descriptor was
             * typically provided by the 'org.apache.sis.internal.referencing.provider' package in
             * order to create the MathTransform associated with the enclosing CRS.  The enclosing
             * CRS is either the immediate parent in WKT 1, or the parent of the parent in WKT 2.
             */
        final FormattableObject parent = formatter.getEnclosingElement(isWKT1 ? 1 : 2);
        if (parent instanceof GeneralDerivedCRS) {
            final Conversion conversion = ((GeneralDerivedCRS) parent).getConversionFromBase();
            if (conversion != null) {
                // Should never be null, but let be safe.
                final ParameterDescriptorGroup descriptor;
                if (conversion instanceof Parameterized) {
                    // Usual case in SIS implementation.
                    descriptor = ((Parameterized) conversion).getParameterDescriptors();
                } else {
                    descriptor = conversion.getParameterValues().getDescriptor();
                }
                name = IdentifiedObjects.getName(descriptor, authority);
            }
        }
        if (name == null) {
            name = IdentifiedObjects.getName(this, null);
            if (name == null) {
                name = Vocabulary.getResources(formatter.getLocale()).getString(Vocabulary.Keys.Unnamed);
                // Because the "Unnamed" string is not a real OperationMethod name.
                kind = ElementKind.NAME;
            }
        }
    }
    formatter.append(name, kind);
    if (isWKT1) {
        /*
             * The WKT 1 keyword is "PROJECTION", which imply that the operation method should be of type
             * org.opengis.referencing.operation.Projection. So strictly speaking only the first check in
             * the following 'if' statement is relevant.
             *
             * Unfortunately in many cases we do not know the operation type, because the method that we
             * invoked - getOperationType() - is not a standard OGC/ISO property, so this information is
             * usually not provided in XML documents for example.  The user could also have instantiated
             * DirectOperationMethod directly without creating a subclass. Consequently we also accept to
             * format the keyword as "PROJECTION" if the operation type *could* be a projection. This is
             * the second check in the following 'if' statement.
             *
             * In other words, the combination of those two checks exclude the following operation types:
             * Transformation, ConcatenatedOperation, PassThroughOperation, or any user-defined type that
             * do not extend Projection. All other operation types are accepted.
             */
        final Class<? extends SingleOperation> type = getOperationType();
        if (Projection.class.isAssignableFrom(type) || type.isAssignableFrom(Projection.class)) {
            return WKTKeywords.Projection;
        }
        formatter.setInvalidWKT(this, null);
    }
    return WKTKeywords.Method;
}
Also used : ElementKind(org.apache.sis.io.wkt.ElementKind) Parameterized(org.apache.sis.parameter.Parameterized) ParameterDescriptorGroup(org.opengis.parameter.ParameterDescriptorGroup) DefaultParameterDescriptorGroup(org.apache.sis.parameter.DefaultParameterDescriptorGroup) Projection(org.opengis.referencing.operation.Projection) GeneralDerivedCRS(org.opengis.referencing.crs.GeneralDerivedCRS) Citation(org.opengis.metadata.citation.Citation) InternationalString(org.opengis.util.InternationalString) SimpleInternationalString(org.apache.sis.util.iso.SimpleInternationalString) FormattableObject(org.apache.sis.io.wkt.FormattableObject) Conversion(org.opengis.referencing.operation.Conversion)

Example 2 with Projection

use of org.opengis.referencing.operation.Projection in project sis by apache.

the class DefaultProjectedCRSTest method testXML.

/**
 * Tests (un)marshalling of a projected coordinate reference system.
 *
 * @throws FactoryException if the CRS creation failed.
 * @throws JAXBException if an error occurred during (un)marshalling.
 */
@Test
public void testXML() throws FactoryException, JAXBException {
    final DefaultProjectedCRS crs = unmarshalFile(DefaultProjectedCRS.class, XML_FILE);
    Validators.validate(crs);
    assertEpsgNameAndIdentifierEqual("NTF (Paris) / Lambert zone II", 27572, crs);
    assertEpsgNameAndIdentifierEqual("NTF (Paris)", 4807, crs.getBaseCRS());
    assertEquals("scope", "Large and medium scale topographic mapping and engineering survey.", crs.getScope().toString());
    assertAxisDirectionsEqual("baseCRS", crs.getBaseCRS().getCoordinateSystem(), AxisDirection.NORTH, AxisDirection.EAST);
    assertAxisDirectionsEqual("coordinateSystem", crs.getCoordinateSystem(), AxisDirection.EAST, AxisDirection.NORTH);
    final Projection conversion = crs.getConversionFromBase();
    assertEpsgNameAndIdentifierEqual("Lambert zone II", 18082, conversion);
    assertEpsgNameAndIdentifierEqual("Lambert Conic Conformal (1SP)", 9801, conversion.getMethod());
    assertNotNull("conversion.mathTransform", conversion.getMathTransform());
    verifyParameters(conversion.getParameterValues());
    /*
         * Test marshalling and compare with the original file. The comparison ignores the <gml:name> nodes because the
         * marshalled CRS contains many operation method and parameter aliases which were not in the original XML file.
         */
    assertMarshalEqualsFile(XML_FILE, crs, null, STRICT, new String[] { "gml:name" }, new String[] { "xmlns:*", "xsi:schemaLocation", "gml:id" });
}
Also used : Projection(org.opengis.referencing.operation.Projection) Test(org.junit.Test)

Example 3 with Projection

use of org.opengis.referencing.operation.Projection in project sis by apache.

the class Proj4 method definition.

/**
 * Infers a {@literal Proj.4} definition from the given projected, geographic or geocentric coordinate reference system.
 * This method does not need the Proj.4 native library; it can be used in a pure Java application.
 * However the returned definition string may differ depending on whether the Proj.4 library is available or not.
 *
 * @param  crs  the coordinate reference system for which to create a Proj.4 definition.
 * @return the definition of the given CRS in a Proj.4 format.
 * @throws FactoryException if the Proj.4 definition string can not be created from the given CRS.
 */
public static String definition(final CoordinateReferenceSystem crs) throws FactoryException {
    ArgumentChecks.ensureNonNull("crs", crs);
    /*
         * If the given CRS object is associated to a Proj.4 structure, let Proj.4 formats itself
         * the definition string. Note that this operation may fail if there is no Proj.4 library
         * in the current system, or no JNI bindings to that library.
         */
    try {
        for (final Identifier id : crs.getIdentifiers()) {
            if (id instanceof PJ) {
                return ((PJ) id).getCode();
            }
        }
    } catch (UnsatisfiedLinkError e) {
        // Thrown the first time that we try to use the library.
        Logging.unexpectedException(Logging.getLogger(Modules.GDAL), Proj4.class, "definition", e);
    } catch (NoClassDefFoundError e) {
        // Thrown on all attempts after the first one.
        Logging.recoverableException(Logging.getLogger(Modules.GDAL), Proj4.class, "definition", e);
    }
    /*
         * If we found no Proj.4 structure, formats the definition string ourself. The string may differ from
         * what Proj.4 would have given. In particular, we do not provide "+init=" or "+datum=" parameter.
         * But the definition should still be semantically equivalent.
         */
    final String method;
    final GeodeticDatum datum;
    final ParameterValueGroup parameters;
    final CoordinateSystem cs = crs.getCoordinateSystem();
    if (crs instanceof GeodeticCRS) {
        if (cs instanceof EllipsoidalCS) {
            method = "latlon";
        } else if (cs instanceof CartesianCS) {
            method = "geocent";
        } else {
            throw new FactoryException(Errors.format(Errors.Keys.UnsupportedCoordinateSystem_1, cs.getClass()));
        }
        datum = ((GeodeticCRS) crs).getDatum();
        parameters = null;
    } else if (crs instanceof ProjectedCRS) {
        Projection c = ((ProjectedCRS) crs).getConversionFromBase();
        datum = ((ProjectedCRS) crs).getDatum();
        method = name(c.getMethod());
        parameters = c.getParameterValues();
    } else {
        throw new FactoryException(Errors.format(Errors.Keys.UnsupportedType_1, crs.getClass()));
    }
    /*
         * Append the map projection parameters. Those parameters may include axis lengths (a and b),
         * but not necessarily. If axis lengths are specified, then we will ignore the Ellipsoid instance
         * associated to the CRS.
         */
    final StringBuilder definition = new StringBuilder(100);
    definition.append(Proj4Factory.PROJ_PARAM).append(method);
    boolean hasSemiMajor = false;
    boolean hasSemiMinor = false;
    if (parameters != null) {
        definition.append(Proj4Factory.STANDARD_OPTIONS);
        for (final GeneralParameterValue parameter : parameters.values()) {
            if (parameter instanceof ParameterValue<?>) {
                final ParameterValue<?> pv = (ParameterValue<?>) parameter;
                final Object value;
                Unit<?> unit = pv.getUnit();
                if (unit != null) {
                    unit = Units.isAngular(unit) ? Units.DEGREE : unit.getSystemUnit();
                    // Always in metres or degrees.
                    value = pv.doubleValue(unit);
                } else {
                    value = pv.getValue();
                    if (value == null) {
                        continue;
                    }
                }
                final String pn = name(parameter.getDescriptor());
                hasSemiMajor |= pn.equals("a");
                hasSemiMinor |= pn.equals("b");
                definition.append(" +").append(pn).append('=').append(value);
            }
        }
    }
    /*
         * Append datum information: axis lengths if they were not part of the parameters, then prime meridian.
         */
    final Ellipsoid ellipsoid = datum.getEllipsoid();
    if (!hasSemiMajor)
        definition.append(" +a=").append(ellipsoid.getSemiMajorAxis());
    if (!hasSemiMinor)
        definition.append(" +b=").append(ellipsoid.getSemiMinorAxis());
    final PrimeMeridian pm = datum.getPrimeMeridian();
    if (pm != null) {
        double lon = pm.getGreenwichLongitude();
        final Unit<Angle> unit = pm.getAngularUnit();
        if (unit != null) {
            lon = unit.getConverterTo(Units.DEGREE).convert(lon);
        }
        definition.append(" +pm=").append(lon);
    }
    /*
         * Appends axis directions. This method always format a vertical direction (up or down)
         * even if the coordinate system is two-dimensional, because Proj.4 seems to require it.
         * Also extract axis units in the process.
         */
    // Horizontal at index 0, vertical at index 1.
    final Unit<?>[] units = new Unit<?>[2];
    boolean validCS = true;
    definition.append(' ').append(Proj4Factory.AXIS_ORDER_PARAM);
    final int dimension = Math.min(cs.getDimension(), 3);
    boolean hasVertical = false;
    for (int i = 0; i < dimension; i++) {
        final CoordinateSystemAxis axis = cs.getAxis(i);
        final AxisDirection dir = axis.getDirection();
        int unitIndex = 0;
        if (!AxisDirections.isCardinal(dir)) {
            if (!AxisDirections.isVertical(dir)) {
                throw new FactoryException(Errors.format(Errors.Keys.UnsupportedAxisDirection_1, dir));
            }
            hasVertical = true;
            unitIndex = 1;
        }
        final Unit<?> old = units[unitIndex];
        units[unitIndex] = axis.getUnit();
        validCS &= (old == null || old.equals(units[unitIndex]));
        definition.appendCodePoint(Character.toLowerCase(dir.name().codePointAt(0)));
    }
    if (!hasVertical && dimension < 3) {
        // Add a UP direction if not already present.
        definition.append('u');
    }
    /*
         * Append units of measurement, then verify the coordinate system validity.
         */
    for (int i = 0; i < units.length; i++) {
        final Unit<?> unit = units[i];
        if (unit != null && !unit.equals(Units.DEGREE) && !unit.equals(Units.METRE)) {
            validCS &= Units.isLinear(unit);
            definition.append(" +");
            // "+vto_meter" parameter.
            if (i == 1)
                definition.append('v');
            definition.append("to_meter=").append(Units.toStandardUnit(unit));
        }
    }
    /*
         * Append the "+towgs84" element if any. This is the last piece of information.
         * Note that the use of a "+towgs84" parameter is an "early binding" approach,
         * which is usually not recommended. But Proj4 works that way.
         */
    if (validCS) {
        if (datum instanceof DefaultGeodeticDatum) {
            for (final BursaWolfParameters bwp : ((DefaultGeodeticDatum) datum).getBursaWolfParameters()) {
                if (Utilities.equalsIgnoreMetadata(CommonCRS.WGS84.datum(), bwp.getTargetDatum())) {
                    definition.append(" +towgs84=").append(bwp.tX).append(',').append(bwp.tY).append(',').append(bwp.tZ);
                    if (!bwp.isTranslation()) {
                        definition.append(',').append(bwp.rX).append(',').append(bwp.rY).append(',').append(bwp.rZ).append(',').append(bwp.dS);
                    }
                    break;
                }
            }
        }
        return definition.toString();
    }
    /*
         * If we reach this point, we detected a coordinate system that we can not format as a
         * Proj.4 definition string. Format an error message with axis directions and units.
         */
    definition.setLength(0);
    definition.append('(');
    for (int i = 0; i < units.length; i++) {
        final CoordinateSystemAxis axis = cs.getAxis(i);
        if (i != 0)
            definition.append(", ");
        definition.append(axis.getUnit()).append(' ').append(Types.getCodeName(axis.getDirection()));
    }
    throw new FactoryException(Errors.format(Errors.Keys.IllegalCoordinateSystem_1, definition.append(')')));
}
Also used : ParameterValueGroup(org.opengis.parameter.ParameterValueGroup) UnavailableFactoryException(org.apache.sis.referencing.factory.UnavailableFactoryException) FactoryException(org.opengis.util.FactoryException) CoordinateSystem(org.opengis.referencing.cs.CoordinateSystem) Projection(org.opengis.referencing.operation.Projection) CoordinateSystemAxis(org.opengis.referencing.cs.CoordinateSystemAxis) Unit(javax.measure.Unit) Identifier(org.opengis.metadata.Identifier) AxisDirection(org.opengis.referencing.cs.AxisDirection) EllipsoidalCS(org.opengis.referencing.cs.EllipsoidalCS) CartesianCS(org.opengis.referencing.cs.CartesianCS) GeneralParameterValue(org.opengis.parameter.GeneralParameterValue) ParameterValue(org.opengis.parameter.ParameterValue) GeneralParameterValue(org.opengis.parameter.GeneralParameterValue) GeodeticDatum(org.opengis.referencing.datum.GeodeticDatum) DefaultGeodeticDatum(org.apache.sis.referencing.datum.DefaultGeodeticDatum) GeodeticCRS(org.opengis.referencing.crs.GeodeticCRS) PrimeMeridian(org.opengis.referencing.datum.PrimeMeridian) ProjectedCRS(org.opengis.referencing.crs.ProjectedCRS) Angle(javax.measure.quantity.Angle) DefaultGeodeticDatum(org.apache.sis.referencing.datum.DefaultGeodeticDatum) IdentifiedObject(org.opengis.referencing.IdentifiedObject) BursaWolfParameters(org.apache.sis.referencing.datum.BursaWolfParameters) Ellipsoid(org.opengis.referencing.datum.Ellipsoid)

Aggregations

Projection (org.opengis.referencing.operation.Projection)3 Unit (javax.measure.Unit)1 Angle (javax.measure.quantity.Angle)1 ElementKind (org.apache.sis.io.wkt.ElementKind)1 FormattableObject (org.apache.sis.io.wkt.FormattableObject)1 DefaultParameterDescriptorGroup (org.apache.sis.parameter.DefaultParameterDescriptorGroup)1 Parameterized (org.apache.sis.parameter.Parameterized)1 BursaWolfParameters (org.apache.sis.referencing.datum.BursaWolfParameters)1 DefaultGeodeticDatum (org.apache.sis.referencing.datum.DefaultGeodeticDatum)1 UnavailableFactoryException (org.apache.sis.referencing.factory.UnavailableFactoryException)1 SimpleInternationalString (org.apache.sis.util.iso.SimpleInternationalString)1 Test (org.junit.Test)1 Identifier (org.opengis.metadata.Identifier)1 Citation (org.opengis.metadata.citation.Citation)1 GeneralParameterValue (org.opengis.parameter.GeneralParameterValue)1 ParameterDescriptorGroup (org.opengis.parameter.ParameterDescriptorGroup)1 ParameterValue (org.opengis.parameter.ParameterValue)1 ParameterValueGroup (org.opengis.parameter.ParameterValueGroup)1 IdentifiedObject (org.opengis.referencing.IdentifiedObject)1 GeneralDerivedCRS (org.opengis.referencing.crs.GeneralDerivedCRS)1