Search in sources :

Example 1 with Convention

use of org.apache.sis.io.wkt.Convention in project sis by apache.

the class ImmutableIdentifier method formatTo.

/**
 * Formats this identifier as a <cite>Well Known Text</cite> {@code Id[…]} element.
 * See class javadoc for more information on the WKT format.
 *
 * @param  formatter  the formatter where to format the inner content of this WKT element.
 * @return {@code "Id"} (WKT 2) or {@code "Authority"} (WKT 1).
 *
 * @see <a href="http://docs.opengeospatial.org/is/12-063r5/12-063r5.html#33">WKT 2 specification §7.3.4</a>
 */
@Override
protected String formatTo(final Formatter formatter) {
    String keyword = null;
    /*
         * The code, codeSpace, authority and version local variables in this method usually have the exact same
         * value than the fields of the same name in this class.  But we get those values by invoking the public
         * methods in order to give to users a chance to override those properties.  The intent is also to use a
         * consistent approach for all 'formatTo' implementations, since some other classes have no choice other
         * than using the public methods.
         */
    final String code = getCode();
    if (code != null) {
        final String codeSpace = getCodeSpace();
        final Citation authority = getAuthority();
        final String cs = (codeSpace != null) ? codeSpace : org.apache.sis.internal.util.Citations.getIdentifier(authority, true);
        if (cs != null) {
            final Convention convention = formatter.getConvention();
            if (convention.majorVersion() == 1) {
                keyword = WKTKeywords.Authority;
                formatter.append(cs, ElementKind.IDENTIFIER);
                formatter.append(code, ElementKind.IDENTIFIER);
            } else {
                keyword = WKTKeywords.Id;
                formatter.append(cs, ElementKind.IDENTIFIER);
                appendCode(formatter, code);
                final String version = getVersion();
                if (version != null) {
                    appendCode(formatter, version);
                }
                /*
                     * In order to simplify the WKT, format the citation only if it is different than the code space.
                     * We will also omit the citation if this identifier is for a parameter value, because parameter
                     * values are handled in a special way by the international standard:
                     *
                     *   - ISO 19162 explicitely said that we shall format the identifier for the root element only,
                     *     and omit the identifier for all inner elements EXCEPT parameter values and operation method.
                     *   - Exclusion of identifier for inner elements is performed by the Formatter class, so it does
                     *     not need to be checked here.
                     *   - Parameter values are numerous, while operation methods typically appear only once in a WKT
                     *     document. So we will simplify the parameter values only (not the operation methods) except
                     *     if the parameter value is the root element (in which case we will format full identifier).
                     */
                final FormattableObject enclosing = formatter.getEnclosingElement(1);
                final boolean isRoot = formatter.getEnclosingElement(2) == null;
                if (isRoot || !(enclosing instanceof ParameterValue<?>)) {
                    final String citation = org.apache.sis.internal.util.Citations.getIdentifier(authority, false);
                    if (citation != null && !citation.equals(cs)) {
                        formatter.append(new Cite(citation));
                    }
                }
                /*
                     * Do not format the optional URI element for internal convention,
                     * because this property is currently computed rather than stored.
                     * Other conventions format only for the ID[…] of root element.
                     */
                if (isRoot && enclosing != null && convention != Convention.INTERNAL) {
                    final String urn = NameMeaning.toURN(enclosing.getClass(), cs, version, code);
                    if (urn != null) {
                        formatter.append(new FormattableObject() {

                            @Override
                            protected String formatTo(final Formatter formatter) {
                                formatter.append(urn, null);
                                return WKTKeywords.URI;
                            }
                        });
                    }
                }
            }
        }
    }
    return keyword;
}
Also used : Convention(org.apache.sis.io.wkt.Convention) Formatter(org.apache.sis.io.wkt.Formatter) InternationalString(org.opengis.util.InternationalString) Citation(org.opengis.metadata.citation.Citation) FormattableObject(org.apache.sis.io.wkt.FormattableObject)

Example 2 with Convention

use of org.apache.sis.io.wkt.Convention in project sis by apache.

the class DefaultGeodeticCRS method formatTo.

/**
 * Formats this CRS as a <cite>Well Known Text</cite> {@code GeodeticCRS[…]} element.
 * More information about the WKT format is documented in subclasses.
 *
 * @return {@code "GeodeticCRS"} (WKT 2) or {@code "GeogCS"}/{@code "GeocCS"} (WKT 1).
 */
@Override
protected String formatTo(final Formatter formatter) {
    WKTUtilities.appendName(this, formatter, null);
    CoordinateSystem cs = getCoordinateSystem();
    final Convention convention = formatter.getConvention();
    final boolean isWKT1 = (convention.majorVersion() == 1);
    final boolean isGeographicWKT1 = isWKT1 && (cs instanceof EllipsoidalCS);
    if (isGeographicWKT1 && cs.getDimension() == 3) {
        /*
             * Version 1 of WKT format did not have three-dimensional GeographicCRS. Instead, such CRS were formatted
             * as a CompoundCRS made of a two-dimensional GeographicCRS with a VerticalCRS for the ellipsoidal height.
             * Note that such compound is illegal in WKT 2 and ISO 19111 standard, as ellipsoidal height shall not be
             * separated from the geographic component. So we perform this separation only at WKT 1 formatting time.
             */
        SingleCRS first = CRS.getHorizontalComponent(this);
        SingleCRS second = CRS.getVerticalComponent(this, true);
        if (first != null && second != null) {
            // Should not be null, but we are paranoiac.
            if (AxisDirection.UP.equals(AxisDirections.absolute(cs.getAxis(0).getDirection()))) {
                // It is very unusual to have VerticalCRS first, but our code tries to be robust.
                final SingleCRS t = first;
                first = second;
                second = t;
            }
            formatter.newLine();
            formatter.append(WKTUtilities.toFormattable(first));
            formatter.newLine();
            formatter.append(WKTUtilities.toFormattable(second));
            formatter.newLine();
            return WKTKeywords.Compd_CS;
        }
    }
    /*
         * Unconditionally format the datum element, followed by the prime meridian.
         * The prime meridian is part of datum according ISO 19111, but is formatted
         * as a sibling (rather than a child) element in WKT for historical reasons.
         */
    // Gives subclasses a chance to override.
    final GeodeticDatum datum = getDatum();
    formatter.newLine();
    formatter.append(WKTUtilities.toFormattable(datum));
    formatter.newLine();
    final PrimeMeridian pm = datum.getPrimeMeridian();
    final Unit<Angle> angularUnit = AxisDirections.getAngularUnit(cs, null);
    if (// Really this specific enum, not Convention.isSimplified().
    convention != Convention.WKT2_SIMPLIFIED || ReferencingUtilities.getGreenwichLongitude(pm, Units.DEGREE) != 0) {
        final Unit<Angle> oldUnit = formatter.addContextualUnit(angularUnit);
        formatter.indent(1);
        formatter.append(WKTUtilities.toFormattable(pm));
        formatter.indent(-1);
        formatter.newLine();
        formatter.restoreContextualUnit(angularUnit, oldUnit);
    }
    /*
         * Get the coordinate system to format. This will also determine the units to write and the keyword to
         * return in WKT 1 format. Note that for the WKT 1 format, we need to replace the coordinate system by
         * an instance conform to the legacy conventions.
         *
         * We can not delegate the work below to subclasses,  because XML unmarshalling of a geodetic CRS will
         * NOT create an instance of a subclass (because the distinction between geographic and geocentric CRS
         * is not anymore in ISO 19111:2007).
         */
    final boolean isBaseCRS;
    if (isWKT1) {
        if (!isGeographicWKT1) {
            // If not geographic, then presumed geocentric.
            if (cs instanceof CartesianCS) {
                cs = Legacy.forGeocentricCRS((CartesianCS) cs, true);
            } else {
                // SphericalCS was not supported in WKT 1.
                formatter.setInvalidWKT(cs, null);
            }
        }
        isBaseCRS = false;
    } else {
        isBaseCRS = isBaseCRS(formatter);
    }
    /*
         * Format the coordinate system, except if this CRS is the base CRS of an AbstractDerivedCRS in WKT 2 format.
         * This is because ISO 19162 omits the coordinate system definition of enclosed base CRS in order to simplify
         * the WKT. The 'formatCS(…)' method may write axis unit before or after the axes depending on whether we are
         * formatting WKT version 1 or 2 respectively.
         *
         * Note that even if we do not format the CS, we may still write the units if we are formatting in "simplified"
         * mode (as opposed to the more verbose mode). This looks like the opposite of what we would expect, but this is
         * because formatting the unit here allow us to avoid repeating the unit in projection parameters when this CRS
         * is part of a ProjectedCRS. Note however that in such case, the units to format are the angular units because
         * the linear units will be formatted in the enclosing PROJCS[…] element.
         */
    if (!isBaseCRS || convention == Convention.INTERNAL) {
        // Will also format the axes unit.
        formatCS(formatter, cs, ReferencingUtilities.getUnit(cs), isWKT1);
    } else if (convention.isSimplified()) {
        formatter.append(formatter.toContextualUnit(angularUnit));
    }
    /*
         * For WKT 1, the keyword depends on the subclass: "GeogCS" for GeographicCRS or "GeocCS" for GeocentricCRS.
         * However we can not rely on the subclass for choosing the keyword, because after XML unmarhaling we only
         * have a GeodeticCRS. We need to make the choice in this base class. The CS type is a sufficient criterion.
         */
    if (isWKT1) {
        return isGeographicWKT1 ? WKTKeywords.GeogCS : WKTKeywords.GeocCS;
    } else {
        return isBaseCRS ? WKTKeywords.BaseGeodCRS : formatter.shortOrLong(WKTKeywords.GeodCRS, WKTKeywords.GeodeticCRS);
    }
}
Also used : SingleCRS(org.opengis.referencing.crs.SingleCRS) CartesianCS(org.opengis.referencing.cs.CartesianCS) Convention(org.apache.sis.io.wkt.Convention) Angle(javax.measure.quantity.Angle) CoordinateSystem(org.opengis.referencing.cs.CoordinateSystem) EllipsoidalCS(org.opengis.referencing.cs.EllipsoidalCS) GeodeticDatum(org.opengis.referencing.datum.GeodeticDatum) PrimeMeridian(org.opengis.referencing.datum.PrimeMeridian)

Example 3 with Convention

use of org.apache.sis.io.wkt.Convention in project sis by apache.

the class DefaultProjectedCRS method formatTo.

/**
 * Formats the inner part of the <cite>Well Known Text</cite> (WKT) representation of this CRS.
 *
 * <div class="note"><b>Example:</b> Well-Known Text (version 2)
 * of a projected coordinate reference system using the Lambert Conformal method.
 *
 * {@preformat wkt
 *   ProjectedCRS[“NTF (Paris) / Lambert zone II”,
 *     BaseGeodCRS[“NTF (Paris)”,
 *       Datum[“Nouvelle Triangulation Francaise”,
 *         Ellipsoid[“NTF”, 6378249.2, 293.4660212936269, LengthUnit[“metre”, 1]]],
 *         PrimeMeridian[“Paris”, 2.5969213, AngleUnit[“grad”, 0.015707963267948967]]],
 *     Conversion[“Lambert zone II”,
 *       Method[“Lambert Conic Conformal (1SP)”, Id[“EPSG”, 9801, Citation[“IOGP”]]],
 *       Parameter[“Latitude of natural origin”, 52.0, AngleUnit[“grad”, 0.015707963267948967], Id[“EPSG”, 8801]],
 *       Parameter[“Longitude of natural origin”, 0.0, AngleUnit[“degree”, 0.017453292519943295], Id[“EPSG”, 8802]],
 *       Parameter[“Scale factor at natural origin”, 0.99987742, ScaleUnit[“unity”, 1], Id[“EPSG”, 8805]],
 *       Parameter[“False easting”, 600000.0, LengthUnit[“metre”, 1], Id[“EPSG”, 8806]],
 *       Parameter[“False northing”, 2200000.0, LengthUnit[“metre”, 1], Id[“EPSG”, 8807]]],
 *     CS[“Cartesian”, 2],
 *       Axis[“Easting (E)”, east, Order[1]],
 *       Axis[“Northing (N)”, north, Order[2]],
 *       LengthUnit[“metre”, 1],
 *     Id[“EPSG”, 27572, Citation[“IOGP”], URI[“urn:ogc:def:crs:EPSG::27572”]]]
 * }
 *
 * <p>Same coordinate reference system using WKT 1.</p>
 *
 * {@preformat wkt
 *   PROJCS[“NTF (Paris) / Lambert zone II”,
 *     GEOGCS[“NTF (Paris)”,
 *       DATUM[“Nouvelle Triangulation Francaise”,
 *         SPHEROID[“NTF”, 6378249.2, 293.4660212936269]],
 *         PRIMEM[“Paris”, 2.33722917],
 *       UNIT[“degree”, 0.017453292519943295],
 *       AXIS[“Longitude”, EAST],
 *       AXIS[“Latitude”, NORTH]],
 *     PROJECTION[“Lambert_Conformal_Conic_1SP”, AUTHORITY[“EPSG”, “9801”]],
 *     PARAMETER[“latitude_of_origin”, 46.8],
 *     PARAMETER[“central_meridian”, 0.0],
 *     PARAMETER[“scale_factor”, 0.99987742],
 *     PARAMETER[“false_easting”, 600000.0],
 *     PARAMETER[“false_northing”, 2200000.0],
 *     UNIT[“metre”, 1],
 *     AXIS[“Easting”, EAST],
 *     AXIS[“Northing”, NORTH],
 *     AUTHORITY[“EPSG”, “27572”]]
 * }
 * </div>
 *
 * @return {@code "ProjectedCRS"} (WKT 2) or {@code "ProjCS"} (WKT 1).
 *
 * @see <a href="http://docs.opengeospatial.org/is/12-063r5/12-063r5.html#57">WKT 2 specification §9</a>
 */
@Override
protected String formatTo(final Formatter formatter) {
    if (super.getConversionFromBase() == null) {
        /*
             * Should never happen except temporarily at construction time, or if the user invoked the copy constructor
             * with an invalid Conversion. 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);
    final CartesianCS cs = getCoordinateSystem();
    final GeographicCRS baseCRS = getBaseCRS();
    final Unit<?> lengthUnit = ReferencingUtilities.getUnit(cs);
    final Unit<Angle> angularUnit = AxisDirections.getAngularUnit(baseCRS.getCoordinateSystem(), null);
    final Unit<Angle> oldAngle = formatter.addContextualUnit(angularUnit);
    final Unit<?> oldLength = formatter.addContextualUnit(lengthUnit);
    /*
         * Format the enclosing base CRS. Note that WKT 1 formats a full GeographicCRS while WKT 2 formats only
         * the datum with the prime meridian (no coordinate system) and uses a different keyword ("BaseGeodCRS"
         * instead of "GeodeticCRS"). The DefaultGeodeticCRS.formatTo(Formatter) method detects when the CRS to
         * format is part of an enclosing ProjectedCRS and will adapt accordingly.
         */
    formatter.newLine();
    formatter.append(toFormattable(baseCRS));
    formatter.newLine();
    final Parameters p = new Parameters(this);
    final boolean isBaseCRS;
    if (isWKT1) {
        // Format outside of any "Conversion" element.
        p.append(formatter);
        isBaseCRS = false;
    } else {
        // Format inside a "Conversion" element.
        formatter.append(p);
        isBaseCRS = isBaseCRS(formatter);
    }
    /*
         * In WKT 2 format, the coordinate system axes are written only if this projected CRS is not the base CRS
         * of another derived CRS.
         */
    if (!isBaseCRS || convention == Convention.INTERNAL) {
        formatCS(formatter, cs, lengthUnit, isWKT1);
    }
    formatter.restoreContextualUnit(lengthUnit, oldLength);
    formatter.restoreContextualUnit(angularUnit, oldAngle);
    return isWKT1 ? WKTKeywords.ProjCS : isBaseCRS ? WKTKeywords.BaseProjCRS : formatter.shortOrLong(WKTKeywords.ProjCRS, WKTKeywords.ProjectedCRS);
}
Also used : CartesianCS(org.opengis.referencing.cs.CartesianCS) Convention(org.apache.sis.io.wkt.Convention) AxesConvention(org.apache.sis.referencing.cs.AxesConvention) Angle(javax.measure.quantity.Angle) GeographicCRS(org.opengis.referencing.crs.GeographicCRS)

Example 4 with Convention

use of org.apache.sis.io.wkt.Convention in project sis by apache.

the class AbstractCRS method formatTo.

/**
 * Formats the inner part of the <cite>Well Known Text</cite> (WKT) representation of this CRS.
 * The default implementation writes the following elements in WKT 2 format:
 *
 * <ul>
 *   <li>The object {@linkplain #getName() name}.</li>
 *   <li>The datum, if any.</li>
 *   <li>All {@linkplain #getCoordinateSystem() coordinate system}'s axis.</li>
 *   <li>The unit if all axes use the same unit, or nothing otherwise.</li>
 * </ul>
 *
 * The WKT 1 format is similar to the WKT 2 one with two differences:
 * <ul>
 *   <li>Units are formatted before the axes instead than after the axes.</li>
 *   <li>If no unit can be formatted because not all axes use the same unit, then the WKT is
 *       {@linkplain Formatter#setInvalidWKT(IdentifiedObject, Exception) flagged as invalid}.</li>
 * </ul>
 *
 * @return {@inheritDoc}
 *
 * @see <a href="http://docs.opengeospatial.org/is/12-063r5/12-063r5.html">WKT 2 specification</a>
 * @see <a href="http://www.geoapi.org/3.0/javadoc/org/opengis/referencing/doc-files/WKT.html">Legacy WKT 1</a>
 */
@Override
protected String formatTo(final Formatter formatter) {
    final String keyword = super.formatTo(formatter);
    formatter.newLine();
    formatter.append(toFormattable(getDatum()));
    formatter.newLine();
    final Convention convention = formatter.getConvention();
    final boolean isWKT1 = convention.majorVersion() == 1;
    if (isWKT1 || convention == Convention.INTERNAL || !isBaseCRS(formatter)) {
        final CoordinateSystem cs = getCoordinateSystem();
        formatCS(formatter, cs, ReferencingUtilities.getUnit(cs), isWKT1);
    }
    return keyword;
}
Also used : Convention(org.apache.sis.io.wkt.Convention) AxesConvention(org.apache.sis.referencing.cs.AxesConvention) CoordinateSystem(org.opengis.referencing.cs.CoordinateSystem)

Example 5 with Convention

use of org.apache.sis.io.wkt.Convention in project sis by apache.

the class DefaultCompoundCRS method formatTo.

/**
 * Formats this CRS as a <cite>Well Known Text</cite> {@code CompoundCRS[…]} element.
 *
 * <div class="section">WKT validity</div>
 * The WKT version 2 format restricts compound CRS to the following components in that order:
 *
 * <ul>
 *   <li>A mandatory horizontal CRS (only one of two-dimensional {@code GeographicCRS}
 *       or {@code ProjectedCRS} or {@code EngineeringCRS}).</li>
 *   <li>Optionally followed by a {@code VerticalCRS} or a {@code ParametricCRS} (but not both).</li>
 *   <li>Optionally followed by a {@code TemporalCRS}.</li>
 * </ul>
 *
 * SIS does not check if this CRS is compliant with the above-cited restrictions.
 *
 * @return {@code "CompoundCRS"} (WKT 2) or {@code "Compd_CS"} (WKT 1).
 *
 * @see <a href="http://docs.opengeospatial.org/is/12-063r5/12-063r5.html#110">WKT 2 specification §16</a>
 */
@Override
protected String formatTo(final Formatter formatter) {
    WKTUtilities.appendName(this, formatter, null);
    final Convention convention = formatter.getConvention();
    final List<? extends CoordinateReferenceSystem> crs;
    final boolean isStandardCompliant;
    final boolean isWKT1 = convention.majorVersion() == 1;
    if (isWKT1 || convention == Convention.INTERNAL) {
        crs = getComponents();
        // WKT 1 does not put any restriction.
        isStandardCompliant = true;
    } else {
        crs = getSingleComponents();
        isStandardCompliant = isStandardCompliant(crs);
    }
    for (final CoordinateReferenceSystem element : crs) {
        formatter.newLine();
        formatter.append(WKTUtilities.toFormattable(element));
    }
    // For writing the ID[…] element on its own line.
    formatter.newLine();
    if (!isStandardCompliant) {
        formatter.setInvalidWKT(this, null);
    }
    return isWKT1 ? WKTKeywords.Compd_CS : WKTKeywords.CompoundCRS;
}
Also used : Convention(org.apache.sis.io.wkt.Convention) AxesConvention(org.apache.sis.referencing.cs.AxesConvention) CoordinateReferenceSystem(org.opengis.referencing.crs.CoordinateReferenceSystem)

Aggregations

Convention (org.apache.sis.io.wkt.Convention)11 AxesConvention (org.apache.sis.referencing.cs.AxesConvention)4 CoordinateSystem (org.opengis.referencing.cs.CoordinateSystem)4 Angle (javax.measure.quantity.Angle)3 Formatter (org.apache.sis.io.wkt.Formatter)2 CartesianCS (org.opengis.referencing.cs.CartesianCS)2 InternationalString (org.opengis.util.InternationalString)2 Length (javax.measure.quantity.Length)1 CS_CoordinateSystem (org.apache.sis.internal.jaxb.referencing.CS_CoordinateSystem)1 FormattableObject (org.apache.sis.io.wkt.FormattableObject)1 DefaultConversion (org.apache.sis.referencing.operation.DefaultConversion)1 Citation (org.opengis.metadata.citation.Citation)1 GeneralParameterValue (org.opengis.parameter.GeneralParameterValue)1 CoordinateReferenceSystem (org.opengis.referencing.crs.CoordinateReferenceSystem)1 GeographicCRS (org.opengis.referencing.crs.GeographicCRS)1 SingleCRS (org.opengis.referencing.crs.SingleCRS)1 AxisDirection (org.opengis.referencing.cs.AxisDirection)1 EllipsoidalCS (org.opengis.referencing.cs.EllipsoidalCS)1 GeodeticDatum (org.opengis.referencing.datum.GeodeticDatum)1 PrimeMeridian (org.opengis.referencing.datum.PrimeMeridian)1