use of org.opengis.referencing.cs.CoordinateSystemAxis in project sis by apache.
the class AbstractEnvelope method getMaximum.
/**
* Returns the maximal ordinate value for the specified dimension. In the typical case
* of non-empty envelopes <em>not</em> spanning the anti-meridian, this method returns the
* {@link #getUpper(int)} value verbatim. In the case of envelope spanning the anti-meridian,
* this method returns the {@linkplain CoordinateSystemAxis#getMaximumValue() axis maximum value}.
* If the range in the given dimension is invalid, then this method returns {@code NaN}.
*
* @param dimension the dimension for which to obtain the ordinate value.
* @return the maximal ordinate value at the given dimension.
* @throws IndexOutOfBoundsException if the given index is negative or is equals or greater
* than the {@linkplain #getDimension() envelope dimension}.
*/
@Override
public double getMaximum(final int dimension) throws IndexOutOfBoundsException {
double upper = getUpper(dimension);
if (isNegative(upper - getLower(dimension))) {
// Special handling for -0.0
final CoordinateSystemAxis axis = getAxis(getCoordinateReferenceSystem(), dimension);
upper = isWrapAround(axis) ? axis.getMaximumValue() : Double.NaN;
}
return upper;
}
use of org.opengis.referencing.cs.CoordinateSystemAxis in project sis by apache.
the class AbstractEnvelope method toSimpleEnvelopes.
/**
* Returns this envelope as an array of simple (without wraparound) envelopes.
* The length of the returned array depends on the number of dimensions where a
* {@linkplain org.opengis.referencing.cs.RangeMeaning#WRAPAROUND wraparound} range is found.
* Typically, wraparound occurs only in the range of longitude values, when the range crosses
* the anti-meridian (a.k.a. date line). However this implementation will take in account any
* axis having wraparound {@linkplain CoordinateSystemAxis#getRangeMeaning() range meaning}.
*
* <p>Special cases:</p>
*
* <ul>
* <li>If this envelope {@linkplain #isEmpty() is empty}, then this method returns an empty array.</li>
* <li>If this envelope does not have any wraparound behavior, then this method returns {@code this}
* in an array of length 1. This envelope is <strong>not</strong> cloned.</li>
* <li>If this envelope crosses the <cite>anti-meridian</cite> (a.k.a. <cite>date line</cite>)
* then this method represents this envelope as two separated simple envelopes.
* <li>While uncommon, the envelope could theoretically crosses the limit of other axis having
* wraparound range meaning. If wraparound occur along <var>n</var> axes, then this method
* represents this envelope as 2ⁿ separated simple envelopes.
* </ul>
*
* @return a representation of this envelope as an array of non-empty envelope.
*
* @see Envelope2D#toRectangles()
* @see GeneralEnvelope#simplify()
*
* @since 0.4
*/
@SuppressWarnings("ReturnOfCollectionOrArrayField")
public Envelope[] toSimpleEnvelopes() {
// A bitmask of the dimensions having a "wrap around" behavior.
long isWrapAround = 0;
CoordinateReferenceSystem crs = null;
final int dimension = getDimension();
for (int i = 0; i != dimension; i++) {
// Do not use getSpan(i).
final double span = getUpper(i) - getLower(i);
if (!(span > 0)) {
// Use '!' for catching NaN.
if (!isNegative(span)) {
// Span is positive zero.
return EMPTY;
}
if (crs == null) {
crs = getCoordinateReferenceSystem();
}
if (!isWrapAround(crs, i)) {
return EMPTY;
}
if (i >= Long.SIZE) {
// a CRS is unusual enough for not being worth to make the distinction in the error message.
throw new IllegalStateException(Errors.format(Errors.Keys.ExcessiveListSize_2, "axis", dimension));
}
isWrapAround |= (1L << i);
}
}
/*
* The number of simple envelopes is 2ⁿ where n is the number of wraparound found. In most
* cases, isWrapAround == 0 so we have an array of length 1 containing only this envelope.
*/
final int bitCount = Long.bitCount(isWrapAround);
if (bitCount >= Integer.SIZE - 1) {
// Should be very unusual, but let be paranoiac.
throw new IllegalStateException(Errors.format(Errors.Keys.ExcessiveListSize_2, "wraparound", bitCount));
}
final Envelope[] envelopes = new Envelope[1 << bitCount];
if (envelopes.length == 1) {
envelopes[0] = this;
} else {
/*
* Need to create at least 2 envelopes. Instantiate now all envelopes with ordinate values
* initialized to a copy of this envelope. We will write directly in their internal arrays later.
*/
double[] c = new double[dimension * 2];
for (int i = 0; i < dimension; i++) {
c[i] = getLower(i);
c[i + dimension] = getUpper(i);
}
final double[][] ordinates = new double[envelopes.length][];
for (int i = 0; i < envelopes.length; i++) {
final GeneralEnvelope envelope = new GeneralEnvelope(i == 0 ? c : c.clone());
envelope.crs = crs;
envelopes[i] = envelope;
ordinates[i] = envelope.ordinates;
}
/*
* Assign the minimum and maximum ordinate values in the dimension where a wraparound has been found.
* The 'for' loop below iterates only over the 'i' values for which the 'isWrapAround' bit is set to 1.
*/
// For identifying whether we need to set the lower or the upper ordinate.
int mask = 1;
@SuppressWarnings("null") final CoordinateSystem // Should not be null at this point.
cs = crs.getCoordinateSystem();
for (int i; (i = Long.numberOfTrailingZeros(isWrapAround)) != Long.SIZE; isWrapAround &= ~(1L << i)) {
final CoordinateSystemAxis axis = cs.getAxis(i);
final double min = axis.getMinimumValue();
final double max = axis.getMaximumValue();
for (int j = 0; j < ordinates.length; j++) {
c = ordinates[j];
if ((j & mask) == 0) {
c[i + dimension] = max;
} else {
c[i] = min;
}
}
mask <<= 1;
}
}
return envelopes;
}
use of org.opengis.referencing.cs.CoordinateSystemAxis in project sis by apache.
the class AbstractEnvelope method getMinimum.
/**
* Returns the minimal ordinate value for the specified dimension. In the typical case
* of non-empty envelopes <em>not</em> spanning the anti-meridian, this method returns the
* {@link #getLower(int)} value verbatim. In the case of envelope spanning the anti-meridian,
* this method returns the {@linkplain CoordinateSystemAxis#getMinimumValue() axis minimum value}.
* If the range in the given dimension is invalid, then this method returns {@code NaN}.
*
* @param dimension the dimension for which to obtain the ordinate value.
* @return the minimal ordinate value at the given dimension.
* @throws IndexOutOfBoundsException if the given index is negative or is equals or greater
* than the {@linkplain #getDimension() envelope dimension}.
*/
@Override
public double getMinimum(final int dimension) throws IndexOutOfBoundsException {
double lower = getLower(dimension);
if (isNegative(getUpper(dimension) - lower)) {
// Special handling for -0.0
final CoordinateSystemAxis axis = getAxis(getCoordinateReferenceSystem(), dimension);
lower = isWrapAround(axis) ? axis.getMinimumValue() : Double.NaN;
}
return lower;
}
use of org.opengis.referencing.cs.CoordinateSystemAxis in project sis by apache.
the class Envelope2D method toRectangles.
/**
* Returns this envelope as non-empty Java2D rectangle objects. This method returns an array of length 0, 1,
* 2 or 4 depending on whether the envelope crosses the anti-meridian or the limit of any other axis having
* {@linkplain org.opengis.referencing.cs.RangeMeaning#WRAPAROUND wraparound} range meaning.
* More specifically:
*
* <ul>
* <li>If this envelope {@linkplain #isEmpty() is empty}, then this method returns an empty array.</li>
* <li>If this envelope does not have any wraparound behavior, then this method returns a copy
* of this envelope as an instance of {@code Rectangle2D.Double} in an array of length 1.</li>
* <li>If this envelope crosses the <cite>anti-meridian</cite> (a.k.a. <cite>date line</cite>)
* then this method represents this envelope as two separated rectangles.
* <li>While uncommon, the envelope could theoretically crosses the limit of other axis having
* wraparound range meaning. If wraparound occur along the two axes, then this method
* represents this envelope as four separated rectangles.
* </ul>
*
* <div class="note"><b>API note:</b>
* The return type is the {@code Rectangle2D.Double} implementation class rather than the {@code Rectangle2D}
* abstract class because the {@code Envelope2D} class hierarchy already exposes this implementation choice.</div>
*
* @return a representation of this envelope as an array of non-empty Java2D rectangles.
* The array never contains {@code this}.
*
* @see GeneralEnvelope#toSimpleEnvelopes()
*
* @since 0.4
*/
@SuppressWarnings("ReturnOfCollectionOrArrayField")
public Rectangle2D.Double[] toRectangles() {
// A bitmask of the dimensions having a "wrap around" behavior.
int isWrapAround = 0;
for (int i = 0; i != DIMENSION; i++) {
final double span = (i == 0) ? width : height;
if (!(span > 0)) {
// Use '!' for catching NaN.
if (!isNegative(span) || !isWrapAround(crs, i)) {
return EMPTY;
}
isWrapAround |= (1 << i);
}
}
/*
* The number of rectangles is 2ⁿ where n is the number of wraparound found.
*/
final Rectangle2D.Double[] rect = new Rectangle2D.Double[1 << Integer.bitCount(isWrapAround)];
for (int i = 0; i < rect.length; i++) {
rect[i] = new Rectangle2D.Double(x, y, width, height);
}
if ((isWrapAround & 1) != 0) {
/*
* (x+width) (x)
* ↓ ↓
* ──────┐ ┌───────
* …next │ │ start…
* ──────┘ └───────
*/
final CoordinateSystemAxis axis = getAxis(crs, 0);
final Rectangle2D.Double start = rect[0];
final Rectangle2D.Double next = rect[1];
start.width = axis.getMaximumValue() - x;
next.x = axis.getMinimumValue();
next.width += x - next.x;
}
if ((isWrapAround & 2) != 0) {
/*
* │ ⋮ │
* │ start │
* (y) → └───────┘
* (y+height) → ┌───────┐
* │ next │
* │ ⋮ │
*/
final CoordinateSystemAxis axis = getAxis(crs, 1);
final Rectangle2D.Double start = rect[0];
// == 1 if y is the only wraparound axis, or 2 otherwise.
final Rectangle2D.Double next = rect[isWrapAround - 1];
start.height = axis.getMaximumValue() - y;
next.y = axis.getMinimumValue();
next.height += y - next.y;
}
if (isWrapAround == 3) {
/*
* If there is a wraparound along both axes, copy the values.
* The (x) and (y) labels indicate which values to copy.
*
* (y) R1 │ │ R0
* ─────────┘ └─────────
* ─────────┐ ┌─────────
* (x,y) R3 │ │ R2 (x)
*/
rect[1].height = rect[0].height;
rect[2].width = rect[0].width;
rect[3].x = rect[1].x;
rect[3].width = rect[1].width;
rect[3].y = rect[2].y;
rect[3].height = rect[2].height;
}
return rect;
}
use of org.opengis.referencing.cs.CoordinateSystemAxis in project sis by apache.
the class Envelope2D method getMinimum.
/**
* Returns the minimal ordinate along the specified dimension. This method handles
* anti-meridian spanning as documented in the {@link AbstractEnvelope#getMinimum(int)}
* method.
*
* @param dimension the dimension to query.
* @return the minimal ordinate value along the given dimension.
* @throws IndexOutOfBoundsException if the given index is out of bounds.
*/
@Override
public double getMinimum(final int dimension) throws IndexOutOfBoundsException {
final double value, span;
switch(dimension) {
case 0:
value = x;
span = width;
break;
case 1:
value = y;
span = height;
break;
default:
throw indexOutOfBounds(dimension);
}
if (isNegative(span)) {
// Special handling for -0.0
final CoordinateSystemAxis axis = getAxis(crs, dimension);
return isWrapAround(axis) ? axis.getMinimumValue() : NaN;
}
return value;
}
Aggregations