Search in sources :

Example 71 with CoordinateReferenceSystem

use of org.opengis.referencing.crs.CoordinateReferenceSystem in project sis by apache.

the class ImageFileDirectory method completeMetadata.

/**
 * Completes the metadata with the information stored in the field of this IFD.
 * This method is invoked only if the user requested the ISO 19115 metadata.
 * This method creates a new {@code "metadata/contentInfo"} node for this image.
 * Information not under the {@code "metadata/contentInfo"} node will be merged
 * with the current content of the given {@code MetadataBuilder}.
 *
 * @param   metadata  where to write metadata information. Caller should have already invoked
 *                    {@link MetadataBuilder#setFormat(String)} before {@code completeMetadata(…)} calls.
 */
final void completeMetadata(final MetadataBuilder metadata, final Locale locale) throws DataStoreContentException, FactoryException {
    metadata.newCoverage(false);
    if (compression != null) {
        metadata.addCompression(compression.name().toLowerCase(locale));
    }
    for (int band = 0; band < samplesPerPixel; ) {
        metadata.newSampleDimension();
        metadata.setBitPerSample(bitsPerSample);
        if (minValues != null)
            metadata.addMinimumSampleValue(minValues.doubleValue(Math.min(band, minValues.size() - 1)));
        if (maxValues != null)
            metadata.addMaximumSampleValue(maxValues.doubleValue(Math.min(band, maxValues.size() - 1)));
        metadata.setBandIdentifier(++band);
    }
    /*
         * Add the resolution into the metadata. Our current ISO 19115 implementation restricts
         * the resolution unit to metres, but it may be relaxed in a future SIS version.
         */
    if (!Double.isNaN(resolution) && resolutionUnit != null) {
        metadata.addResolution(resolutionUnit.getConverterTo(Units.METRE).convert(resolution));
    }
    /*
         * Cell size is relevant only if the Threshholding TIFF tag value is 2. By convention in
         * this implementation class, other Threshholding values are stored as negative cell sizes:
         *
         *   -1 means that Threshholding is 1 or unspecified.
         *   -2 means that Threshholding is 2 but the matrix size has not yet been specified.
         *   -3 means that Threshholding is 3 (randomized process such as error diffusion).
         */
    switch(Math.min(cellWidth, cellHeight)) {
        case -1:
            {
                // Nothing to report.
                break;
            }
        case -3:
            {
                metadata.addProcessDescription(Resources.formatInternational(Resources.Keys.RandomizedProcessApplied));
                break;
            }
        default:
            {
                metadata.addProcessDescription(Resources.formatInternational(Resources.Keys.DitheringOrHalftoningApplied_2, (cellWidth >= 0) ? cellWidth : '?', (cellHeight >= 0) ? cellHeight : '?'));
                break;
            }
    }
    /*
         * Add Coordinate Reference System built from GeoTIFF tags.  Note that the CRS may not exist,
         * in which case the CRS builder returns null. This is safe since all MetadataBuilder methods
         * ignore null values (a design choice because this pattern come very often).
         */
    final boolean isGeorectified = (modelTiePoints == null) || (gridToCRS != null);
    metadata.newGridRepresentation(isGeorectified ? MetadataBuilder.GridType.GEORECTIFIED : MetadataBuilder.GridType.GEOREFERENCEABLE);
    metadata.setGeoreferencingAvailability(gridToCRS != null, false, false);
    CoordinateReferenceSystem crs = null;
    if (geoKeyDirectory != null) {
        final CRSBuilder helper = new CRSBuilder(reader);
        try {
            crs = helper.build(geoKeyDirectory, numericGeoParameters, asciiGeoParameters);
            metadata.addReferenceSystem(crs);
            helper.complete(metadata);
        } catch (NoSuchIdentifierException | ParameterNotFoundException e) {
            short key = Resources.Keys.UnsupportedProjectionMethod_1;
            if (e instanceof NoSuchAuthorityCodeException) {
                key = Resources.Keys.UnknownCRS_1;
            }
            reader.owner.warning(reader.resources().getString(key, reader.owner.getDisplayName()), e);
        } catch (IllegalArgumentException | NoSuchElementException | ClassCastException e) {
            if (!helper.alreadyReported) {
                reader.owner.warning(null, e);
            }
        }
    }
    try {
        if (!isGeorectified) {
            metadata.addGeolocation(new GridGeometry(filename(), crs, modelTiePoints));
        }
    } catch (TransformException e) {
        reader.owner.warning(null, e);
    }
    // Not needed anymore, so let GC do its work.
    geoKeyDirectory = null;
    numericGeoParameters = null;
    asciiGeoParameters = null;
    modelTiePoints = null;
}
Also used : NoSuchAuthorityCodeException(org.opengis.referencing.NoSuchAuthorityCodeException) TransformException(org.opengis.referencing.operation.TransformException) NoSuchIdentifierException(org.opengis.util.NoSuchIdentifierException) CoordinateReferenceSystem(org.opengis.referencing.crs.CoordinateReferenceSystem) ParameterNotFoundException(org.opengis.parameter.ParameterNotFoundException) NoSuchElementException(java.util.NoSuchElementException)

Example 72 with CoordinateReferenceSystem

use of org.opengis.referencing.crs.CoordinateReferenceSystem in project sis by apache.

the class TransformCommand method run.

/**
 * Transforms coordinates from the files given in argument or from the standard input stream.
 *
 * @return 0 on success, or an exit code if the command failed for a reason other than an uncaught Java exception.
 */
@Override
public int run() throws Exception {
    final CoordinateReferenceSystem sourceCRS = fetchCRS(Option.SOURCE_CRS);
    final CoordinateReferenceSystem targetCRS = fetchCRS(Option.TARGET_CRS);
    /*
         * Read all coordinates, so we can compute the area of interest.
         * This will be used when searching for a coordinate operation.
         */
    GeographicBoundingBox areaOfInterest = null;
    List<double[]> points = Collections.emptyList();
    final boolean useStandardInput = useStandardInput();
    if (useStandardInput || !files.isEmpty()) {
        if (useStandardInput) {
            try (LineNumberReader in = new LineNumberReader(new InputStreamReader(System.in, encoding))) {
                points = readCoordinates(in, "stdin");
            }
        } else {
            for (final String file : files) {
                try (LineNumberReader in = new LineNumberReader(new InputStreamReader(new FileInputStream(file), encoding))) {
                    points = readCoordinates(in, file);
                }
            }
        }
        try {
            final GeographicCRS domainOfValidityCRS = ReferencingUtilities.toNormalizedGeographicCRS(sourceCRS);
            if (domainOfValidityCRS != null) {
                toDomainOfValidity = CRS.findOperation(sourceCRS, domainOfValidityCRS, null).getMathTransform();
                areaOfInterest = computeAreaOfInterest(points);
            }
        } catch (FactoryException e) {
            warning(e);
        }
    }
    operation = CRS.findOperation(sourceCRS, targetCRS, areaOfInterest);
    /*
         * Prints the header: source CRS, target CRS, operation steps and positional accuracy.
         */
    outHeader = new TableAppender(new LineAppender(out), " ");
    outHeader.setMultiLinesCells(true);
    printHeader(Vocabulary.Keys.Source);
    printNameAndIdentifier(operation.getSourceCRS(), false);
    printHeader(Vocabulary.Keys.Destination);
    printNameAndIdentifier(operation.getTargetCRS(), false);
    printHeader(Vocabulary.Keys.Operations);
    printOperations(operation, false);
    outHeader.nextLine();
    printDomainOfValidity(operation.getDomainOfValidity());
    printAccuracy(CRS.getLinearAccuracy(operation));
    if (options.containsKey(Option.VERBOSE)) {
        printDetails();
    }
    outHeader.flush();
    outHeader = null;
    /*
         * At this point we finished to write the header. If there is at least one input file,
         * compute the number of digits to format and perform the actual coordinate operations.
         */
    if (!points.isEmpty()) {
        // Must be set before computeNumFractionDigits(…).
        ordinateWidth = 15;
        coordinateFormat = NumberFormat.getInstance(Locale.US);
        coordinateFormat.setGroupingUsed(false);
        computeNumFractionDigits(operation.getTargetCRS().getCoordinateSystem());
        out.println();
        printAxes(operation.getTargetCRS().getCoordinateSystem());
        out.println();
        transform(points);
        if (errorMessage != null) {
            error(errorMessage, errorCause);
        }
    }
    return 0;
}
Also used : InputStreamReader(java.io.InputStreamReader) FactoryException(org.opengis.util.FactoryException) TableAppender(org.apache.sis.io.TableAppender) CoordinateReferenceSystem(org.opengis.referencing.crs.CoordinateReferenceSystem) GeographicBoundingBox(org.opengis.metadata.extent.GeographicBoundingBox) DefaultGeographicBoundingBox(org.apache.sis.metadata.iso.extent.DefaultGeographicBoundingBox) InternationalString(org.opengis.util.InternationalString) GeographicCRS(org.opengis.referencing.crs.GeographicCRS) LineAppender(org.apache.sis.io.LineAppender) FileInputStream(java.io.FileInputStream) LineNumberReader(java.io.LineNumberReader)

Example 73 with CoordinateReferenceSystem

use of org.opengis.referencing.crs.CoordinateReferenceSystem in project sis by apache.

the class CRS method suggestCommonTarget.

/**
 * Suggests a coordinate reference system which could be a common target for coordinate operations having the
 * given sources. This method compares the {@linkplain #getGeographicBoundingBox(CoordinateReferenceSystem)
 * domain of validity} of all given CRSs. If a CRS has a domain of validity that contains the domain of all other
 * CRS, than that CRS is returned. Otherwise this method verifies if a {@linkplain GeneralDerivedCRS#getBaseCRS()
 * base CRS} (usually a {@linkplain org.apache.sis.referencing.crs.DefaultGeographicCRS geographic CRS} instance)
 * would be suitable. If no suitable CRS is found, then this method returns {@code null}.
 *
 * <div class="note"><b>Use case:</b>
 * before to test if two arbitrary envelopes {@linkplain GeneralEnvelope#intersects(Envelope) intersect} each other,
 * they need to be {@linkplain Envelopes#transform(Envelope, CoordinateReferenceSystem) transformed} in the same CRS.
 * However if one CRS is a Transverse Mercator projection while the other CRS is a world-wide geographic CRS, then
 * attempts to use the Transverse Mercator projection as the common CRS is likely to fail since the geographic envelope
 * may span an area far outside the projection domain of validity. This {@code suggestCommonTarget(…)} method can used
 * for choosing a common CRS which is less likely to fail.</div>
 *
 * @param  regionOfInterest  the geographic area for which the coordinate operations will be applied,
 *                           or {@code null} if unknown.
 * @param  sourceCRS         the coordinate reference systems for which a common target CRS is desired.
 * @return a CRS that may be used as a common target for all the given source CRS in the given region of interest,
 *         or {@code null} if this method did not find a common target CRS. The returned CRS may be different than
 *         all given CRS.
 *
 * @since 0.8
 */
public static CoordinateReferenceSystem suggestCommonTarget(GeographicBoundingBox regionOfInterest, CoordinateReferenceSystem... sourceCRS) {
    CoordinateReferenceSystem bestCRS = null;
    /*
         * Compute the union of the domain of validity of all CRS. If a CRS does not specify a domain of validity,
         * then assume that the CRS is valid for the whole world if the CRS is geodetic or return null otherwise.
         * Opportunistically remember the domain of validity of each CRS in this loop since we will need them later.
         */
    boolean worldwide = false;
    DefaultGeographicBoundingBox domain = null;
    final GeographicBoundingBox[] domains = new GeographicBoundingBox[sourceCRS.length];
    for (int i = 0; i < sourceCRS.length; i++) {
        final CoordinateReferenceSystem crs = sourceCRS[i];
        final GeographicBoundingBox bbox = getGeographicBoundingBox(crs);
        if (bbox == null) {
            /*
                 * If no domain of validity is specified and we can not fallback
                 * on some knowledge about what the CRS is, abandon.
                 */
            if (!(crs instanceof GeodeticCRS)) {
                return null;
            }
            /*
                 * Geodetic CRS (geographic or geocentric) can generally be presumed valid in a worldwide area.
                 * The 'worldwide' flag is a little optimization for remembering that we do not need to compute
                 * the union anymore, but we still need to continue the loop for fetching all bounding boxes.
                 */
            // Fallback to be used if we don't find anything better.
            bestCRS = crs;
            worldwide = true;
        } else {
            domains[i] = bbox;
            if (!worldwide) {
                if (domain == null) {
                    domain = new DefaultGeographicBoundingBox(bbox);
                } else {
                    domain.add(bbox);
                }
            }
        }
    }
    /*
         * At this point we got the union of the domain of validity of all CRS. We are interested only in the
         * part that intersect the region of interest. If the union is whole world, we do not need to compute
         * the intersection; we can just leave the region of interest unchanged.
         */
    if (domain != null && !worldwide) {
        if (regionOfInterest != null) {
            domain.intersect(regionOfInterest);
        }
        regionOfInterest = domain;
        domain = null;
    }
    /*
         * Iterate again over the domain of validity of all CRS.  For each domain of validity, compute the area
         * which is inside the domain or interest and the area which is outside. The "best CRS" will be the one
         * which comply with the following rules, in preference order:
         *
         *   1) The CRS which is valid over the largest area of the region of interest.
         *   2) If two CRS are equally good according rule 1, then the CRS with the smallest "outside area".
         *
         * Example: given two source CRS, a geographic one and a projected one:
         *
         *   - If the projected CRS contains fully the region of interest, then it will be returned.
         *     The preference is given to the projected CRS because geometric are likely to be more
         *     accurate in that space. Furthermore forward conversions from geographic to projected
         *     CRS are usually faster than inverse conversions.
         *
         *   - Otherwise (i.e. if the region of interest is likely to be wider than the projected CRS
         *     domain of validity), then the geographic CRS will be returned.
         */
    // NaN if 'regionOfInterest' is null.
    final double roiArea = Extents.area(regionOfInterest);
    double maxInsideArea = 0;
    double minOutsideArea = Double.POSITIVE_INFINITY;
    boolean tryDerivedCRS = false;
    do {
        for (int i = 0; i < domains.length; i++) {
            final GeographicBoundingBox bbox = domains[i];
            if (bbox != null) {
                double insideArea = Extents.area(bbox);
                double outsideArea = 0;
                if (regionOfInterest != null) {
                    if (domain == null) {
                        domain = new DefaultGeographicBoundingBox(bbox);
                    } else {
                        domain.setBounds(bbox);
                    }
                    domain.intersect(regionOfInterest);
                    final double area = insideArea;
                    insideArea = Extents.area(domain);
                    outsideArea = area - insideArea;
                }
                if (insideArea > maxInsideArea || (insideArea == maxInsideArea && outsideArea < minOutsideArea)) {
                    maxInsideArea = insideArea;
                    minOutsideArea = outsideArea;
                    bestCRS = sourceCRS[i];
                }
            }
        }
        /*
             * If the best CRS does not cover fully the region of interest, then we will redo the check again
             * but using base CRS instead. For example if the list of source CRS had some projected CRS, we
             * will try with the geographic CRS on which those projected CRS are based.
             */
        if (maxInsideArea < roiArea) {
            // Do not try twice.
            if (tryDerivedCRS)
                break;
            final CoordinateReferenceSystem[] derivedCRS = new CoordinateReferenceSystem[sourceCRS.length];
            for (int i = 0; i < derivedCRS.length; i++) {
                GeographicBoundingBox bbox = null;
                final CoordinateReferenceSystem crs = sourceCRS[i];
                if (crs instanceof GeneralDerivedCRS) {
                    final CoordinateReferenceSystem baseCRS = ((GeneralDerivedCRS) crs).getBaseCRS();
                    bbox = getGeographicBoundingBox(baseCRS);
                    if (bbox == null && bestCRS == null && baseCRS instanceof GeodeticCRS) {
                        // Fallback to be used if we don't find anything better.
                        bestCRS = baseCRS;
                    }
                    tryDerivedCRS = true;
                    derivedCRS[i] = baseCRS;
                }
                domains[i] = bbox;
            }
            sourceCRS = derivedCRS;
        } else {
            break;
        }
    } while (tryDerivedCRS);
    return bestCRS;
}
Also used : DefaultGeographicBoundingBox(org.apache.sis.metadata.iso.extent.DefaultGeographicBoundingBox) GeneralDerivedCRS(org.opengis.referencing.crs.GeneralDerivedCRS) CoordinateReferenceSystem(org.opengis.referencing.crs.CoordinateReferenceSystem) GeographicBoundingBox(org.opengis.metadata.extent.GeographicBoundingBox) DefaultGeographicBoundingBox(org.apache.sis.metadata.iso.extent.DefaultGeographicBoundingBox) GeodeticCRS(org.opengis.referencing.crs.GeodeticCRS)

Example 74 with CoordinateReferenceSystem

use of org.opengis.referencing.crs.CoordinateReferenceSystem in project sis by apache.

the class DefaultCompoundCRS method verify.

/**
 * Verifies that the given array does not contain duplicated horizontal or vertical components.
 * Verifies also that if there is an horizontal component, then there is no ellipsoidal height
 * defined separately.
 *
 * @param  properties  the user-specified properties, for determining the locale of error messages.
 * @param  components  the components to verify.
 */
private static void verify(final Map<String, ?> properties, final CoordinateReferenceSystem[] components) {
    int allTypes = 0;
    // 0 for false, 1 for true.
    int isProjected = 0;
    boolean isEllipsoidalHeight = false;
    for (final CoordinateReferenceSystem component : components) {
        final int type;
        if (component instanceof GeodeticCRS) {
            // Must match the number used in Resources.Keys.DuplicatedSpatialComponents_1.
            type = 1;
        } else if (component instanceof ProjectedCRS) {
            isProjected = 1;
            // Intentionally same number than for GeographicCRS case.
            type = 1;
        } else if (component instanceof VerticalCRS) {
            isEllipsoidalHeight = ReferencingUtilities.isEllipsoidalHeight(((VerticalCRS) component).getDatum());
            // Must match the number used in Resources.Keys.DuplicatedSpatialComponents_1.
            type = 2;
        } else {
            // Skip other types. In particular, we allow 2 temporal CRS (used in meteorology).
            continue;
        }
        if (allTypes == (allTypes |= type)) {
            throw new IllegalArgumentException(Resources.forProperties(properties).getString(Resources.Keys.DuplicatedSpatialComponents_1, type));
        }
    }
    if (isEllipsoidalHeight && ((allTypes & 1) != 0)) {
        throw new IllegalArgumentException(Resources.forProperties(properties).getString(Resources.Keys.EllipsoidalHeightNotAllowed_1, isProjected));
    }
}
Also used : ProjectedCRS(org.opengis.referencing.crs.ProjectedCRS) VerticalCRS(org.opengis.referencing.crs.VerticalCRS) CoordinateReferenceSystem(org.opengis.referencing.crs.CoordinateReferenceSystem) GeodeticCRS(org.opengis.referencing.crs.GeodeticCRS)

Example 75 with CoordinateReferenceSystem

use of org.opengis.referencing.crs.CoordinateReferenceSystem in project sis by apache.

the class DefaultCompoundCRS method createCoordinateSystem.

/**
 * Returns a compound coordinate system for the specified array of CRS objects.
 *
 * @param  properties  the properties given to the constructor, or {@code null} if unknown.
 * @param  components  the CRS components, usually singles but not necessarily.
 * @return the coordinate system for the given components.
 */
private static CoordinateSystem createCoordinateSystem(final Map<String, ?> properties, final CoordinateReferenceSystem[] components) {
    ArgumentChecks.ensureNonNull("components", components);
    verify(properties, components);
    if (components.length < 2) {
        throw new IllegalArgumentException(Errors.getResources(properties).getString(Errors.Keys.TooFewArguments_2, 2, components.length));
    }
    final CoordinateSystem[] cs = new CoordinateSystem[components.length];
    for (int i = 0; i < components.length; i++) {
        final CoordinateReferenceSystem crs = components[i];
        ArgumentChecks.ensureNonNullElement("components", i, crs);
        cs[i] = crs.getCoordinateSystem();
    }
    return new DefaultCompoundCS(cs);
}
Also used : CoordinateSystem(org.opengis.referencing.cs.CoordinateSystem) CoordinateReferenceSystem(org.opengis.referencing.crs.CoordinateReferenceSystem) DefaultCompoundCS(org.apache.sis.referencing.cs.DefaultCompoundCS)

Aggregations

CoordinateReferenceSystem (org.opengis.referencing.crs.CoordinateReferenceSystem)210 Test (org.junit.Test)80 MathTransform (org.opengis.referencing.operation.MathTransform)32 FactoryException (org.opengis.referencing.FactoryException)25 CoordinateOperation (org.opengis.referencing.operation.CoordinateOperation)24 ReferencedEnvelope (org.geotools.geometry.jts.ReferencedEnvelope)23 Geometry (com.vividsolutions.jts.geom.Geometry)21 TransformException (org.opengis.referencing.operation.TransformException)21 DependsOnMethod (org.apache.sis.test.DependsOnMethod)19 CoordinateSystem (org.opengis.referencing.cs.CoordinateSystem)13 Geometry (org.locationtech.jts.geom.Geometry)11 FactoryException (org.opengis.util.FactoryException)11 SimpleFeature (org.opengis.feature.simple.SimpleFeature)9 DirectPosition (org.opengis.geometry.DirectPosition)9 GeographicCRS (org.opengis.referencing.crs.GeographicCRS)9 VerticalCRS (org.opengis.referencing.crs.VerticalCRS)9 CoordinateSystemAxis (org.opengis.referencing.cs.CoordinateSystemAxis)9 ArrayList (java.util.ArrayList)8 GeometryType (org.opengis.feature.type.GeometryType)8 RevFeatureType (org.locationtech.geogig.api.RevFeatureType)7