This is an automated email from the ASF dual-hosted git repository. desruisseaux pushed a commit to branch geoapi-4.0 in repository https://gitbox.apache.org/repos/asf/sis.git
commit 5bdc8570d0f93df290ae89f63ceeeaa849f6257f Author: Martin Desruisseaux <[email protected]> AuthorDate: Thu Jan 3 19:56:28 2019 +0100 Moved the "reduce" method for keeping it close to "compound". --- .../main/java/org/apache/sis/referencing/CRS.java | 172 +++++++++++---------- 1 file changed, 88 insertions(+), 84 deletions(-) diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/CRS.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/CRS.java index 8218765..e91666d 100644 --- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/CRS.java +++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/CRS.java @@ -932,6 +932,93 @@ public final class CRS extends Static { } /** + * Gets or creates a coordinate reference system with a subset of the dimensions of the given CRS. + * This method can be used for dimensionality reduction. + * + * @param crs the CRS to reduce the dimensionality, or {@code null} if none. + * @param dimensions the dimensions to retain. The dimensions will be taken in increasing order, ignoring duplicated values. + * @return a coordinate reference system for the given dimensions. May be the given {@code crs}, which may be {@code null}. + * @throws IllegalArgumentException if the given array is empty or if the array contains invalid indices. + * @throws FactoryException if the geodetic factory failed to create a compound CRS. + * + * @see #getComponentAt(CoordinateReferenceSystem, int, int) + * @see #compound(CoordinateReferenceSystem...) + * + * @since 1.0 + */ + public static CoordinateReferenceSystem reduce(final CoordinateReferenceSystem crs, final int... dimensions) throws FactoryException { + ArgumentChecks.ensureNonNull("dimensions", dimensions); + if (crs == null) { + return null; + } + final int dimension = ReferencingUtilities.getDimension(crs); + long selected = 0; + for (final int d : dimensions) { + if (d < 0 || d >= dimension) { + throw new IndexOutOfBoundsException(Errors.format(Errors.Keys.IndexOutOfBounds_1, d)); + } + if (d >= Long.SIZE) { + throw new IllegalArgumentException(Errors.format(Errors.Keys.ExcessiveNumberOfDimensions_1, d)); + } + selected |= (1L << d); + } + if (selected == 0) { + throw new IllegalArgumentException(Errors.format(Errors.Keys.EmptyArgument_1, "dimensions")); + } + final List<CoordinateReferenceSystem> components = new ArrayList<>(Long.bitCount(selected)); + reduce(0, crs, dimension, selected, components); + return compound(components.toArray(new CoordinateReferenceSystem[components.size()])); + } + + /** + * Adds the components of reduced CRS into the given list. + * This method may invoke itself recursively for walking through compound CRS. + * + * @param previous number of dimensions of previous CRS. + * @param crs the CRS for which to select components. + * @param dimension number of dimensions of {@code crs}. + * @param selected bitmask of dimensions to select. + * @param addTo where to add CRS components. + * @return new bitmask after removal of dimensions of the components added to {@code addTo}. + */ + private static long reduce(int previous, final CoordinateReferenceSystem crs, int dimension, long selected, + final List<CoordinateReferenceSystem> addTo) throws FactoryException + { + final long current = (Numerics.bitmask(dimension) - 1) << previous; + final long intersect = selected & current; + if (intersect != 0) { + if (intersect == current) { + addTo.add(crs); + selected &= ~current; + } else if (crs instanceof CompoundCRS) { + for (final CoordinateReferenceSystem component : ((CompoundCRS) crs).getComponents()) { + dimension = ReferencingUtilities.getDimension(component); + selected = reduce(previous, component, dimension, selected, addTo); + if ((selected & current) == 0) break; // Stop if it would be useless to continue. + previous += dimension; + } + } else if (dimension == 3 && crs instanceof SingleCRS) { + final Datum datum = ((SingleCRS) crs).getDatum(); + if (datum instanceof GeodeticDatum) { + final boolean isVertical = Long.bitCount(intersect) == 1; // Presumed for now, verified later. + final int verticalDimension = Long.numberOfTrailingZeros((isVertical ? intersect : ~intersect) >>> previous); + final CoordinateSystemAxis verticalAxis = crs.getCoordinateSystem().getAxis(verticalDimension); + if (AxisDirections.isVertical(verticalAxis.getDirection())) try { + addTo.add(new EllipsoidalHeightSeparator((GeodeticDatum) datum).separate((SingleCRS) crs, isVertical)); + selected &= ~current; + } catch (IllegalArgumentException | ClassCastException e) { + throw new FactoryException(Resources.format(Resources.Keys.CanNotSeparateCRS_1, crs.getName())); + } + } + } + } + if ((selected & current) != 0) { + throw new FactoryException(Resources.format(Resources.Keys.CanNotSeparateCRS_1, crs.getName())); + } + return selected; + } + + /** * Returns {@code true} if the given CRS is horizontal. The current implementation considers a * CRS as horizontal if it is two-dimensional and comply with one of the following conditions: * @@ -1254,6 +1341,7 @@ public final class CRS extends Static { * or can not be decomposed for dimensions in the [{@code lower} … {@code upper}] range. * @throws IndexOutOfBoundsException if the given index are out of bounds. * + * @see #reduce(CoordinateReferenceSystem, int...) * @see org.apache.sis.geometry.GeneralEnvelope#subEnvelope(int, int) * * @since 0.5 @@ -1287,90 +1375,6 @@ check: while (lower != 0 || upper != dimension) { } /** - * Gets or creates a coordinate reference system with a subset of the dimensions of the given CRS. - * This method can be used for dimensionality reduction. - * - * @param crs the CRS to reduce the dimensionality, or {@code null} if none. - * @param dimensions the dimensions to retain. The dimensions will be taken in increasing order, ignoring duplicated values. - * @return a coordinate reference system for the given dimensions. May be the given {@code crs}, which may be {@code null}. - * @throws IllegalArgumentException if the given array is empty or if the array contains invalid indices. - * @throws FactoryException if the geodetic factory failed to create a compound CRS. - * - * @since 1.0 - */ - public static CoordinateReferenceSystem reduce(final CoordinateReferenceSystem crs, final int... dimensions) throws FactoryException { - ArgumentChecks.ensureNonNull("dimensions", dimensions); - if (crs == null) { - return null; - } - final int dimension = ReferencingUtilities.getDimension(crs); - if (dimension > Long.SIZE) { - throw new IllegalArgumentException(Errors.format(Errors.Keys.ExcessiveNumberOfDimensions_1, dimension)); - } - long selected = 0; - for (final int d : dimensions) { - if (d < 0 || d >= dimension) { - throw new IndexOutOfBoundsException(Errors.format(Errors.Keys.IndexOutOfBounds_1, d)); - } - selected |= (1L << d); - } - if (selected == 0) { - throw new IllegalArgumentException(Errors.format(Errors.Keys.EmptyArgument_1, "dimensions")); - } - final List<CoordinateReferenceSystem> components = new ArrayList<>(Long.bitCount(selected)); - reduce(0, crs, dimension, selected, components); - return compound(components.toArray(new CoordinateReferenceSystem[components.size()])); - } - - /** - * Adds the components of reduced CRS into the given list. - * This method may invoke itself recursively for walking through compound CRS. - * - * @param previous number of dimensions of previous CRS. - * @param crs the CRS for which to select components. - * @param dimension number of dimensions of {@code crs}. - * @param selected bitmask of dimensions to select. - * @param addTo where to add CRS components. - * @return new bitmask after removal of dimensions of the components added to {@code addTo}. - */ - private static long reduce(int previous, final CoordinateReferenceSystem crs, int dimension, long selected, - final List<CoordinateReferenceSystem> addTo) throws FactoryException - { - final long current = (Numerics.bitmask(dimension) - 1) << previous; - final long intersect = selected & current; - if (intersect != 0) { - if (intersect == current) { - addTo.add(crs); - selected &= ~current; - } else if (crs instanceof CompoundCRS) { - for (final CoordinateReferenceSystem component : ((CompoundCRS) crs).getComponents()) { - dimension = ReferencingUtilities.getDimension(component); - selected = reduce(previous, component, dimension, selected, addTo); - if ((selected & current) == 0) break; // Stop if it would be useless to continue. - previous += dimension; - } - } else if (dimension == 3 && crs instanceof SingleCRS) { - final Datum datum = ((SingleCRS) crs).getDatum(); - if (datum instanceof GeodeticDatum) { - final boolean isVertical = Long.bitCount(intersect) == 1; // Presumed for now, verified later. - final int verticalDimension = Long.numberOfTrailingZeros((isVertical ? intersect : ~intersect) >>> previous); - final CoordinateSystemAxis verticalAxis = crs.getCoordinateSystem().getAxis(verticalDimension); - if (AxisDirections.isVertical(verticalAxis.getDirection())) try { - addTo.add(new EllipsoidalHeightSeparator((GeodeticDatum) datum).separate((SingleCRS) crs, isVertical)); - selected &= ~current; - } catch (IllegalArgumentException | ClassCastException e) { - throw new FactoryException(Resources.format(Resources.Keys.CanNotSeparateCRS_1, crs.getName())); - } - } - } - } - if ((selected & current) != 0) { - throw new FactoryException(Resources.format(Resources.Keys.CanNotSeparateCRS_1, crs.getName())); - } - return selected; - } - - /** * Returns the Greenwich longitude of the prime meridian of the given CRS in degrees. * If the prime meridian uses an other unit than degrees, then the value will be converted. *
