blob: 7d34fe120ef72a997134cddd096ff90d0f029698 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.sis.geometry;
/*
* Do not add dependency to java.awt.Rectangle2D in this class, because not every platforms
* support Java2D (e.g. Android), or applications that do not need it may want to avoid to
* force installation of the Java2D module (e.g. JavaFX/SWT).
*/
import java.util.Arrays;
import java.util.Objects;
/**
* A view over a sub-set of the dimensions of a {@link GeneralEnvelope}.
* This class doesn't keep any reference to the original envelope;
* only the internal array is shared.
*
* @author Martin Desruisseaux (Geomatys)
*/
final class SubEnvelope extends GeneralEnvelope {
/**
* For cross-version compatibility.
*/
private static final long serialVersionUID = 7241242611077979466L;
/**
* The index of the first valid coordinate value of the lower corner in the {@link #coordinates} array.
*
* @see ArrayEnvelope#beginIndex()
*/
private final int beginIndex;
/**
* The index after the last valid coordinate value of the lower corner in the {@link #coordinates} array.
*
* @see ArrayEnvelope#endIndex()
*/
private final int endIndex;
/**
* Creates a new envelope over a portion of the given array. This constructor stores the given
* reference directly; it does <strong>not</strong> clone the given array. This is the desired
* behavior for allowing the {@code SubEnvelope} view to be "live".
*
* @param coordinates the array of coordinate values to store directly (not cloned).
* @param beginIndex the index of the first valid coordinate value of the lower corner in the coordinates array.
* @param endIndex the index after the last valid coordinate value of the lower corner in the coordinates array.
*/
SubEnvelope(final double[] coordinates, final int beginIndex, final int endIndex) {
super(coordinates);
this.beginIndex = beginIndex;
this.endIndex = endIndex;
}
/**
* Returns the index of the first valid coordinate value of the lower corner in the coordinates array.
* This information is used by super-class methods.
*/
@Override
final int beginIndex() {
return beginIndex;
}
/**
* Returns the index after the last valid coordinate value of the lower corner in the coordinates array.
* This information is used by super-class methods.
*/
@Override
final int endIndex() {
return endIndex;
}
/**
* Returns the number of dimensions in the portion of the array used by this {@code SubEnvelope}.
*/
@Override
public int getDimension() {
return endIndex - beginIndex;
}
/**
* Must be overridden, since the super-class method does not handle the index range
* for performance reasons.
*/
@Override
public double getLower(final int dimension) throws IndexOutOfBoundsException {
return coordinates[Objects.checkIndex(dimension, endIndex) + beginIndex];
}
/**
* Must be overridden, since the super-class method does not handle the index range
* for performance reasons.
*/
@Override
public double getUpper(final int dimension) throws IndexOutOfBoundsException {
return coordinates[Objects.checkIndex(dimension, endIndex) + beginIndex + (coordinates.length >>> 1)];
}
/**
* Must be overridden, since the super-class method processes the full array as a whole.
*/
@Override
public void setRange(int dimension, final double lower, final double upper)
throws IndexOutOfBoundsException
{
Objects.checkIndex(dimension, endIndex);
/*
* The check performed here shall be identical to the super-class method, which is itself
* identical to ArrayEnvelope.verifyRanges(crs, coordinates) except that there is no loop.
*/
if (lower > upper && crs != null && !isWrapAround(crs, dimension)) {
throw new IllegalArgumentException(illegalRange(crs, dimension, lower, upper));
}
dimension += beginIndex;
coordinates[dimension + (coordinates.length >>> 1)] = upper;
coordinates[dimension] = lower;
}
/**
* Must be overridden, since the super-class method processes the full array as a whole.
*/
@Override
public void setEnvelope(final double... corners) {
final int dimension = getDimension();
verifyArrayLength(dimension, corners);
verifyRanges(crs, corners);
final int d = coordinates.length >>> 1;
System.arraycopy(corners, 0, coordinates, beginIndex, dimension);
System.arraycopy(corners, dimension, coordinates, beginIndex + d, dimension);
}
/**
* Must be overridden, since the super-class method processes the full array as a whole.
*/
@Override
public boolean isAllNaN() {
final int d = coordinates.length >>> 1;
for (int i=beginIndex; i<endIndex; i++) {
if (!Double.isNaN(coordinates[i]) || !Double.isNaN(coordinates[i+d])) {
return false;
}
}
assert isEmpty() : this;
return true;
}
/**
* Must be overridden, since the super-class method processes the full array as a whole.
*/
@Override
public void setToNaN() {
final int d = coordinates.length >>> 1;
Arrays.fill(coordinates, beginIndex, endIndex, Double.NaN);
Arrays.fill(coordinates, beginIndex+d, endIndex+d, Double.NaN);
assert isAllNaN() : this;
}
/**
* Must be overridden, since the super-class method processes the full array as a whole.
*/
@Override
public int hashCode() {
return hashCodeByAPI();
}
/**
* Must be overridden, since the super-class method processes the full array as a whole.
*/
@Override
public boolean equals(final Object object) {
return equalsByAPI(object);
}
/**
* Must be overridden, since the super-class method does not handle the index range
* for performance reasons.
*/
@Override
public GeneralEnvelope subEnvelope(final int b, final int e) throws IndexOutOfBoundsException {
Objects.checkFromToIndex(b, e, endIndex - beginIndex);
return new SubEnvelope(coordinates, b + beginIndex, e + beginIndex);
}
/**
* If the user wants a clone, copy only the relevant part of the coordinates array.
*/
@Override
@SuppressWarnings("CloneDoesntCallSuperClone")
public GeneralEnvelope clone() {
final int d = coordinates.length >>> 1;
final int dimension = endIndex - beginIndex;
final GeneralEnvelope copy = new GeneralEnvelope(endIndex - beginIndex);
System.arraycopy(coordinates, beginIndex, copy.coordinates, 0, dimension);
System.arraycopy(coordinates, beginIndex + d, copy.coordinates, dimension, dimension);
copy.crs = crs;
return copy;
}
}