use of org.opengis.metadata.extent.GeographicBoundingBox in project sis by apache.
the class ServicesForMetadata method setBounds.
/**
* Sets the geographic, vertical and temporal extents with the values inferred from the given envelope.
* If the given {@code target} has more geographic or vertical extents than needed (0 or 1), then the
* extraneous extents are removed.
*
* @param envelope the source envelope.
* @param target the target spatiotemporal extent where to store envelope information.
* @throws TransformException if no temporal component can be extracted from the given envelope.
*/
@Override
public void setBounds(final Envelope envelope, final DefaultSpatialTemporalExtent target) throws TransformException {
final CoordinateReferenceSystem crs = envelope.getCoordinateReferenceSystem();
final SingleCRS horizontalCRS = CRS.getHorizontalComponent(crs);
final VerticalCRS verticalCRS = CRS.getVerticalComponent(crs, true);
final TemporalCRS temporalCRS = CRS.getTemporalComponent(crs);
if (horizontalCRS == null && verticalCRS == null && temporalCRS == null) {
throw new TransformException(dimensionNotFound(Resources.Keys.MissingSpatioTemporalDimension_1, crs));
}
/*
* Try to set the geographic bounding box first, because this operation may fail with a
* TransformException while the other operations (vertical and temporal) should not fail.
* So doing the geographic part first help us to get a "all or nothing" behavior.
*/
DefaultGeographicBoundingBox box = null;
boolean useExistingBox = (horizontalCRS != null);
final Collection<GeographicExtent> spatialExtents = target.getSpatialExtent();
final Iterator<GeographicExtent> it = spatialExtents.iterator();
while (it.hasNext()) {
final GeographicExtent extent = it.next();
if (extent instanceof GeographicBoundingBox) {
if (useExistingBox && (extent instanceof DefaultGeographicBoundingBox)) {
box = (DefaultGeographicBoundingBox) extent;
useExistingBox = false;
} else {
it.remove();
}
}
}
if (horizontalCRS != null) {
if (box == null) {
box = new DefaultGeographicBoundingBox();
spatialExtents.add(box);
}
GeographicCRS normalizedCRS = ReferencingUtilities.toNormalizedGeographicCRS(crs);
if (normalizedCRS == null) {
normalizedCRS = CommonCRS.defaultGeographic();
}
setGeographicExtent(envelope, box, crs, normalizedCRS);
}
/*
* Other dimensions (vertical and temporal).
*/
if (verticalCRS != null) {
VerticalExtent e = target.getVerticalExtent();
if (!(e instanceof DefaultVerticalExtent)) {
e = new DefaultVerticalExtent();
target.setVerticalExtent(e);
}
setVerticalExtent(envelope, (DefaultVerticalExtent) e, crs, verticalCRS);
} else {
target.setVerticalExtent(null);
}
if (temporalCRS != null) {
setTemporalExtent(envelope, target, crs, temporalCRS);
} else {
target.setExtent(null);
}
}
use of org.opengis.metadata.extent.GeographicBoundingBox in project sis by apache.
the class LocationFormat method format.
/**
* Writes a textual representation of the given location in the given stream or buffer.
*
* <div class="warning"><b>Upcoming API change — generalization</b><br>
* in a future SIS version, the type of {@code location} parameter may be generalized
* to the {@code org.opengis.referencing.gazetteer.Location} interface.
* This change is pending GeoAPI revision.</div>
*
* @param location the location to format.
* @param toAppendTo where to format the location.
* @throws IOException if an error occurred while writing to the given appendable.
*/
@Override
@SuppressWarnings({ "fallthrough", "null" })
public void format(final AbstractLocation location, final Appendable toAppendTo) throws IOException {
ArgumentChecks.ensureNonNull("location", location);
final Locale locale = getLocale(Locale.Category.DISPLAY);
final Vocabulary vocabulary = Vocabulary.getResources(locale);
final TableAppender table = new TableAppender(toAppendTo, "│ ", columnSeparator, " │");
table.setMultiLinesCells(true);
/*
* Location type.
*/
table.appendHorizontalSeparator();
final AbstractLocationType type = location.type();
if (type != null) {
append(table, vocabulary, Vocabulary.Keys.LocationType, toString(type.getName(), locale));
}
/*
* Geographic identifier and alternative identifiers, if any.
*/
append(table, vocabulary, Vocabulary.Keys.GeographicIdentifier, toString(location.getGeographicIdentifier(), locale));
final Collection<? extends InternationalString> alt = location.getAlternativeGeographicIdentifiers();
if (alt != null && !alt.isEmpty()) {
boolean isFirst = true;
vocabulary.appendLabel(Vocabulary.Keys.AlternativeIdentifiers, table);
nextColumn(table);
for (final InternationalString id : alt) {
if (!isFirst) {
isFirst = false;
table.append(lineSeparator);
}
table.append(id);
}
table.nextLine();
}
/*
* Extents (temporal and geographic). If an envelope exists and the CRS is not geographic,
* then the envelope bounds will be appended on the same lines than the geographic bounds.
* But before writing the bounding box and/or the envelope, check if they are redundant.
* We may also need to change axis order (but not unit) of the envelope in order to match
* the axis order of the geographic bounding box.
*/
final Extent extent = new DefaultExtent(null, location.getGeographicExtent(), null, location.getTemporalExtent());
final Range<Date> time = Extents.getTimeRange(extent);
if (time != null) {
append(table, vocabulary, Vocabulary.Keys.StartDate, toString(time.getMinValue()));
append(table, vocabulary, Vocabulary.Keys.EndDate, toString(time.getMaxValue()));
}
GeographicBoundingBox bbox = Extents.getGeographicBoundingBox(extent);
Envelope envelope = location.getEnvelope();
DirectPosition position = position(location.getPosition());
// Position in geographic CRS.
DirectPosition geopos = null;
// Envelope Coordinate Reference System.
CoordinateReferenceSystem crs = null;
// CRS in conventional (x,y) axis order.
CoordinateReferenceSystem normCRS = null;
// If failed to transform envelope.
Exception warning = null;
try {
if (envelope != null) {
normCRS = normalize(crs = envelope.getCoordinateReferenceSystem());
if (normCRS != crs) {
// Should only change order and sign.
envelope = Envelopes.transform(envelope, normCRS);
}
}
if (position != null) {
/*
* If only one of the envelope or the position objects specify a CRS, assume that the other object
* use the same CRS. If both the envelope and the position objects specify a CRS, the envelope CRS
* will have precedence and the "representative position" will be projected to that CRS.
*/
final CoordinateReferenceSystem posCRS = position.getCoordinateReferenceSystem();
if (normCRS == null) {
normCRS = normalize(crs = posCRS);
if (normCRS != crs) {
// Should only change order and sign.
envelope = Envelopes.transform(envelope, normCRS);
}
}
if (bbox != null) {
// Compute geographic position only if there is a geographic bounding box.
GeographicCRS geogCRS = ReferencingUtilities.toNormalizedGeographicCRS(posCRS);
if (geogCRS != null) {
geopos = transform(position, posCRS, geogCRS);
}
}
position = transform(position, posCRS, normCRS);
}
} catch (FactoryException | TransformException e) {
envelope = null;
position = null;
warning = e;
}
/*
* At this point we got the final geographic bounding box and/or envelope to write.
* Since we will write the projected and geographic coordinates side-by-side in the same cells,
* we need to format them in advance so we can compute their width for internal right-alignment.
* We do the alignment ourselves instead than using TableAppender.setCellAlignment(ALIGN_RIGHT)
* because we do not want (projected geographic) tuple to appear far on the right side if other
* cells have long texts.
*/
if (bbox != null || envelope != null) {
final CoordinateSystem cs = (crs != null) ? crs.getCoordinateSystem() : null;
String[] geographic = null;
String[] projected = null;
String[] unitSymbol = null;
AngleFormat geogFormat = null;
NumberFormat projFormat = null;
UnitFormat unitFormat = null;
int maxGeogLength = 0;
int maxProjLength = 0;
int maxUnitLength = 0;
boolean showProj = false;
if (bbox != null || geopos != null) {
geogFormat = (AngleFormat) getFormat(Angle.class);
geographic = new String[BOUND_KEY.length];
Arrays.fill(geographic, "");
}
if (envelope != null || position != null) {
projFormat = (NumberFormat) getFormat(Number.class);
unitFormat = (UnitFormat) getFormat(Unit.class);
projected = new String[BOUND_KEY.length];
unitSymbol = new String[BOUND_KEY.length];
Arrays.fill(projected, "");
Arrays.fill(unitSymbol, "");
}
for (int i = 0; i < BOUND_KEY.length; i++) {
RoundingMode rounding = RoundingMode.FLOOR;
double g = Double.NaN;
double p = Double.NaN;
int dimension = 0;
switch(i) {
case 0:
if (bbox != null)
g = bbox.getWestBoundLongitude();
if (envelope != null)
p = envelope.getMinimum(0);
break;
case 2:
if (bbox != null)
g = bbox.getEastBoundLongitude();
if (envelope != null)
p = envelope.getMaximum(0);
rounding = RoundingMode.CEILING;
break;
case 3:
if (bbox != null)
g = bbox.getSouthBoundLatitude();
if (envelope != null)
p = envelope.getMinimum(1);
dimension = 1;
break;
case 5:
if (bbox != null)
g = bbox.getNorthBoundLatitude();
if (envelope != null)
p = envelope.getMaximum(1);
rounding = RoundingMode.CEILING;
dimension = 1;
break;
// Fall through
case 4:
dimension = 1;
case 1:
if (geopos != null)
g = geopos.getOrdinate(dimension);
if (position != null)
p = position.getOrdinate(dimension);
rounding = RoundingMode.HALF_EVEN;
break;
}
if (!Double.isNaN(p)) {
showProj |= (g != p);
if (cs != null) {
final Unit<?> unit = cs.getAxis(dimension).getUnit();
if (unit != null) {
final int length = (unitSymbol[i] = unitFormat.format(unit)).length();
if (length > maxUnitLength) {
maxUnitLength = length;
}
}
}
try {
projFormat.setRoundingMode(rounding);
} catch (UnsupportedOperationException e) {
// Ignore.
}
final int length = (projected[i] = projFormat.format(p)).length();
if (length > maxProjLength) {
maxProjLength = length;
}
}
if (!Double.isNaN(g)) {
geogFormat.setRoundingMode(rounding);
final Angle angle = (dimension == 0) ? new Longitude(g) : new Latitude(g);
final int length = (geographic[i] = geogFormat.format(angle)).length();
if (length > maxGeogLength) {
maxGeogLength = length;
}
}
}
if (!showProj) {
// All projected coordinates are identical to geographic ones.
projected = null;
unitSymbol = null;
maxProjLength = 0;
maxUnitLength = 0;
} else if (maxProjLength != 0) {
if (maxUnitLength != 0) {
maxUnitLength++;
}
// Arbitrary space between projected and geographic coordinates.
maxGeogLength += 4;
}
/*
* At this point all coordinates have been formatted in advance.
*/
final String separator = (projected != null && geographic != null) ? " —" : "";
for (int i = 0; i < BOUND_KEY.length; i++) {
final String p = (projected != null) ? projected[i] : "";
final String u = (unitSymbol != null) ? unitSymbol[i] : "";
final String g = (geographic != null) ? geographic[i] : "";
if (!p.isEmpty() || !g.isEmpty()) {
vocabulary.appendLabel(BOUND_KEY[i], table);
nextColumn(table);
table.append(CharSequences.spaces(maxProjLength - p.length())).append(p);
table.append(CharSequences.spaces(maxUnitLength - u.length())).append(u).append(separator);
table.append(CharSequences.spaces(maxGeogLength - g.length())).append(g);
table.nextLine();
}
}
}
if (crs != null) {
append(table, vocabulary, Vocabulary.Keys.CoordinateRefSys, IdentifiedObjects.getName(crs, null));
}
/*
* Organization responsible for defining the characteristics of the location instance.
*/
final AbstractParty administrator = location.getAdministrator();
if (administrator != null) {
append(table, vocabulary, Vocabulary.Keys.Administrator, toString(administrator.getName(), locale));
}
table.appendHorizontalSeparator();
table.flush();
if (warning != null) {
vocabulary.appendLabel(Vocabulary.Keys.Warnings, toAppendTo);
toAppendTo.append(warning.toString()).append(lineSeparator);
}
}
use of org.opengis.metadata.extent.GeographicBoundingBox in project sis by apache.
the class TransformerTest method test3D_to_2D.
/**
* Same test than {@link #testIdentity()} except that the height values are dropped.
*
* @throws FactoryException if an error occurred while creating the object.
* @throws DataStoreException if an error occurred while reading a data file.
*/
@Test
@DependsOnMethod("testIdentity")
public void test3D_to_2D() throws FactoryException, DataStoreException {
final double[][] points = { new double[] { 30, 20, 4 }, new double[] { 34, 17, -3 }, new double[] { 27, -12, 12 }, new double[] { 32, 23, -1 } };
final double[][] result = { new double[] { 30, 20 }, new double[] { 34, 17 }, new double[] { 27, -12 }, new double[] { 32, 23 } };
final Transformer tr = new Transformer(caller, CommonCRS.WGS84.geographic3D(), "EPSG:4326", points);
// False if there is no EPSG geodetic dataset installed.
assumeTrue(tr.hasAreaOfInterest());
final GeographicBoundingBox bbox = tr.getAreaOfInterest();
assertEquals("eastBoundLongitude", 23, bbox.getEastBoundLongitude(), STRICT);
assertEquals("westBoundLongitude", -12, bbox.getWestBoundLongitude(), STRICT);
assertEquals("northBoundLatitude", 34, bbox.getNorthBoundLatitude(), STRICT);
assertEquals("southBoundLatitude", 27, bbox.getSouthBoundLatitude(), STRICT);
assertPointsEqual(result, tr.transform(points), STRICT);
}
use of org.opengis.metadata.extent.GeographicBoundingBox in project sis by apache.
the class TransformerTest method testIdentity.
/**
* Tests a trivial identity operation. The main purpose of this method is to test the constructor.
*
* @throws FactoryException if an error occurred while creating the object.
* @throws DataStoreException if an error occurred while reading a data file.
*/
@Test
public void testIdentity() throws FactoryException, DataStoreException {
final double[][] points = { new double[] { 30, 20 }, new double[] { 34, 17 }, new double[] { 27, -12 }, new double[] { 32, 23 } };
final Transformer tr = new Transformer(caller, CommonCRS.WGS84.geographic(), "EPSG:4326", points);
// False if there is no EPSG geodetic dataset installed.
assumeTrue(tr.hasAreaOfInterest());
final GeographicBoundingBox bbox = tr.getAreaOfInterest();
assertEquals("eastBoundLongitude", 23, bbox.getEastBoundLongitude(), STRICT);
assertEquals("westBoundLongitude", -12, bbox.getWestBoundLongitude(), STRICT);
assertEquals("northBoundLatitude", 34, bbox.getNorthBoundLatitude(), STRICT);
assertEquals("southBoundLatitude", 27, bbox.getSouthBoundLatitude(), STRICT);
assertPointsEqual(points, tr.transform(points), STRICT);
}
use of org.opengis.metadata.extent.GeographicBoundingBox in project sis by apache.
the class ReferencingFunctions method getGeographicArea.
/**
* Returns the domain of validity as a geographic bounding box for an identified object.
* This method returns a 2×2 matrix:
* the first row contains the latitude and longitude of upper left corner,
* and the second row contains the latitude and longitude of bottom right corner.
* Units are degrees.
*
* @param codeOrPath the code allocated by an authority, or the path to a file.
* @return the object bounding box.
*/
@Override
public double[][] getGeographicArea(final String codeOrPath) {
final CacheKey<GeographicBoundingBox> key = new CacheKey<>(GeographicBoundingBox.class, codeOrPath, null, null);
GeographicBoundingBox area = key.peek();
if (area == null) {
final Cache.Handler<GeographicBoundingBox> handler = key.lock();
try {
area = handler.peek();
if (area == null)
try {
final IdentifiedObject object = getIdentifiedObject(codeOrPath, null);
final Object domain = IdentifiedObjects.getProperties(object).get(ReferenceSystem.DOMAIN_OF_VALIDITY_KEY);
if (domain instanceof Extent) {
area = Extents.getGeographicBoundingBox((Extent) domain);
}
} catch (Exception exception) {
reportException("getGeographicArea", exception);
}
} finally {
handler.putAndUnlock(area);
}
}
if (area == null) {
return new double[][] {};
}
return new double[][] { new double[] { area.getNorthBoundLatitude(), area.getWestBoundLongitude() }, new double[] { area.getSouthBoundLatitude(), area.getEastBoundLongitude() } };
}
Aggregations